aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2021-11-03 13:19:24 +0100
committerGitHub <noreply@github.com>2021-11-03 13:19:24 +0100
commite74f05326c81fc4977dde31759fa7d3d75155641 (patch)
treef746ee2cebd97e5a6b1ef74e747b568d4e03554e /controller-server
parente5bc78b971380cb1245e9c6a36c2b3ea0fe6eebf (diff)
parent41bf6baf7256cfa2619457bb47a935b61d0e7a7b (diff)
Merge pull request #19842 from vespa-engine/ogronnesby/end-date-inclusive
Make the bill end date inclusive instead of exclusive
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java36
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view3
5 files changed, 38 insertions, 29 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
index b8c8ce4e63a..3afc2c8fc15 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
@@ -111,8 +111,8 @@ public class BillingApiHandler extends LoggingRequestHandler {
.map(bill -> {
return new Object[] {
bill.id().value(), bill.tenant().value(),
- bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE),
- bill.getEndTime().format(DateTimeFormatter.ISO_LOCAL_DATE),
+ bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE),
+ bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE),
bill.sumCpuHours(), bill.sumMemoryHours(), bill.sumDiskHours(),
bill.sumCpuCost(), bill.sumMemoryCost(), bill.sumDiskCost(),
bill.sumAdditionalCost()
@@ -246,7 +246,7 @@ public class BillingApiHandler extends LoggingRequestHandler {
LocalDate startDate = LocalDate.parse(getInspectorFieldOrThrow(inspector, "startTime"));
LocalDate endDate = LocalDate.parse(getInspectorFieldOrThrow(inspector, "endTime"));
ZonedDateTime startTime = startDate.atStartOfDay(ZoneId.of("UTC"));
- ZonedDateTime endTime = endDate.atStartOfDay(ZoneId.of("UTC"));
+ ZonedDateTime endTime = endDate.plusDays(1).atStartOfDay(ZoneId.of("UTC"));
var billId = billingController.createBillForPeriod(tenantName, startTime, endTime, userId);
@@ -332,7 +332,7 @@ public class BillingApiHandler extends LoggingRequestHandler {
if (currentUsage == null) return;
cursor.setString("amount", currentUsage.sum().toPlainString());
cursor.setString("status", "accrued");
- cursor.setString("from", currentUsage.getStartTime().format(DATE_TIME_FORMATTER));
+ cursor.setString("from", currentUsage.getStartDate().format(DATE_TIME_FORMATTER));
var itemsCursor = cursor.setArray("items");
currentUsage.lineItems().forEach(lineItem -> {
var itemCursor = itemsCursor.addObject();
@@ -363,8 +363,8 @@ public class BillingApiHandler extends LoggingRequestHandler {
private void renderBillToCursor(Cursor billCursor, Bill bill) {
billCursor.setString("id", bill.id().value());
- billCursor.setString("from", bill.getStartTime().format(DATE_TIME_FORMATTER));
- billCursor.setString("to", bill.getEndTime().format(DATE_TIME_FORMATTER));
+ billCursor.setString("from", bill.getStartDate().format(DATE_TIME_FORMATTER));
+ billCursor.setString("to", bill.getEndDate().format(DATE_TIME_FORMATTER));
billCursor.setString("amount", bill.sum().toString());
billCursor.setString("status", bill.status());
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
index 101321e4da3..f18d38e971b 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
@@ -35,6 +35,7 @@ import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
+import java.util.logging.Level;
/**
* @author ogronnesby
@@ -178,7 +179,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
private Slime tenantUsage(RestApi.RequestContext requestContext) {
var tenantName = TenantName.from(requestContext.pathParameters().getStringOrThrow("tenant"));
var tenant = tenants.require(tenantName, CloudTenant.class);
- var untilAt = untilParameter(requestContext);
+ var untilAt = untilParameter(requestContext).orElseGet(clock::instant);
var usage = billing.createUncommittedBill(tenant.name(), untilAt.atZone(ZoneOffset.UTC).toLocalDate());
var slime = new Slime();
@@ -189,7 +190,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
// --------- ACCOUNTANT API ----------
private Slime accountant(RestApi.RequestContext requestContext) {
- var untilAt = untilParameter(requestContext);
+ var untilAt = untilParameter(requestContext).orElseGet(clock::instant);
var usagePerTenant = billing.createUncommittedBills(untilAt.atZone(ZoneOffset.UTC).toLocalDate());
var response = new Slime();
@@ -200,7 +201,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
tenantResponse.setString("tenant", tenant.name().value());
tenantResponse.setString("plan", billing.getPlan(tenant.name()).value());
tenantResponse.setString("collection", billing.getCollectionMethod(tenant.name()).name());
- tenantResponse.setString("lastBill", usage.map(Bill::getStartTime).map(DateTimeFormatter.ISO_DATE::format).orElse(null));
+ tenantResponse.setString("lastBill", usage.map(Bill::getStartDate).map(DateTimeFormatter.ISO_DATE::format).orElse(null));
tenantResponse.setString("unbilled", usage.map(Bill::sum).map(BigDecimal::toPlainString).orElse("0.00"));
});
@@ -210,7 +211,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
private Slime previewBill(RestApi.RequestContext requestContext) {
var tenantName = TenantName.from(requestContext.pathParameters().getStringOrThrow("tenant"));
var tenant = tenants.require(tenantName, CloudTenant.class);
- var untilAt = untilParameter(requestContext);
+ var untilAt = untilParameter(requestContext).orElseGet(this::startOfDayTodayUTC);
var usage = billing.createUncommittedBill(tenant.name(), untilAt.atZone(ZoneOffset.UTC).toLocalDate());
@@ -229,7 +230,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
var tenant = tenants.require(tenantName, CloudTenant.class);
var startAt = LocalDate.parse(getInspectorFieldOrThrow(body, "from")).atStartOfDay(ZoneOffset.UTC);
- var endAt = LocalDate.parse(getInspectorFieldOrThrow(body, "to")).atStartOfDay(ZoneOffset.UTC);
+ var endAt = LocalDate.parse(getInspectorFieldOrThrow(body, "to")).plusDays(1).atStartOfDay(ZoneOffset.UTC);
var invoiceId = billing.createBillForPeriod(tenant.name(), startAt, endAt, security.principal().getName());
@@ -246,23 +247,23 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
private void invoiceSummaryToSlime(Cursor slime, Bill bill) {
slime.setString("id", bill.id().value());
- slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
- slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("to", bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("total", bill.sum().toString());
slime.setString("status", bill.status());
}
private void usageToSlime(Cursor slime, Bill bill) {
- slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
- slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("to", bill.getEndTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("total", bill.sum().toString());
toSlime(slime.setArray("items"), bill.lineItems());
}
private void toSlime(Cursor slime, Bill bill) {
slime.setString("id", bill.id().value());
- slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
- slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+ slime.setString("to", bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("total", bill.sum().toString());
slime.setString("status", bill.status());
toSlime(slime.setArray("statusHistory"), bill.statusHistory());
@@ -308,8 +309,8 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
private List<Object[]> toCsv(Bill bill) {
return List.<Object[]>of(new Object[]{
bill.id().value(), bill.tenant().value(),
- bill.getStartTime().format(DateTimeFormatter.ISO_DATE),
- bill.getEndTime().format(DateTimeFormatter.ISO_DATE),
+ bill.getStartDate().format(DateTimeFormatter.ISO_DATE),
+ bill.getEndDate().format(DateTimeFormatter.ISO_DATE),
bill.sumCpuHours(), bill.sumMemoryHours(), bill.sumDiskHours(),
bill.sumCpuCost(), bill.sumMemoryCost(), bill.sumDiskCost(),
bill.sumAdditionalCost()
@@ -318,11 +319,14 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
// ---------- END INVOICE RENDERING ----------
- private Instant untilParameter(RestApi.RequestContext ctx) {
+ private Optional<Instant> untilParameter(RestApi.RequestContext ctx) {
return ctx.queryParameters().getString("until")
.map(LocalDate::parse)
- .map(date -> date.plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant())
- .orElseGet(clock::instant);
+ .map(date -> date.plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant());
+ }
+
+ private Instant startOfDayTodayUTC() {
+ return LocalDate.now(clock.withZone(ZoneOffset.UTC)).atStartOfDay(ZoneOffset.UTC).toInstant();
}
private static String getInspectorFieldOrThrow(Inspector inspector, String field) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
index 3c4ed8bc8df..74ed1a0bb10 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
@@ -122,8 +122,11 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
bills = billingController.getBillsForTenant(tenant);
assertEquals(1, bills.size());
Bill bill = bills.get(0);
- assertEquals(bill.getStartTime().toString(), "2020-04-20T00:00Z[UTC]");
- assertEquals(bill.getEndTime().toString(), "2020-05-20T00:00Z[UTC]");
+ assertEquals("2020-04-20T00:00Z[UTC]", bill.getStartTime().toString());
+ assertEquals("2020-05-21T00:00Z[UTC]", bill.getEndTime().toString());
+
+ assertEquals("2020-04-20", bill.getStartDate().toString());
+ assertEquals("2020-05-20", bill.getEndDate().toString());
}
@Test
@@ -223,7 +226,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
static Bill createBill() {
var start = LocalDate.of(2020, 5, 23).atStartOfDay(ZoneOffset.UTC);
- var end = start.plusDays(5);
+ var end = start.toLocalDate().plusDays(6).atStartOfDay(ZoneOffset.UTC);
var statusHistory = new Bill.StatusHistory(new TreeMap<>(Map.of(start, "OPEN")));
return new Bill(
Bill.Id.of("id-1"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java
index 178cb6f9909..c41616dbba5 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java
@@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec;
import org.junit.Before;
import org.junit.Test;
+import java.time.Duration;
import java.time.Instant;
import java.util.Set;
@@ -105,10 +106,10 @@ public class BillingApiHandlerV2Test extends ControllerContainerCloudTest {
@Test
public void require_tenant_invoice() {
var listRequest = request("/billing/v2/tenant/" + tenant + "/bill").roles(tenantReader);
- tester.assertResponse(listRequest, "{\"invoices\":[{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-23\",\"total\":\"123.00\",\"status\":\"OPEN\"}]}");
+ tester.assertResponse(listRequest, "{\"invoices\":[{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-28\",\"total\":\"123.00\",\"status\":\"OPEN\"}]}");
var singleRequest = request("/billing/v2/tenant/" + tenant + "/bill/id-1").roles(tenantReader);
- tester.assertResponse(singleRequest, "{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-23\",\"total\":\"123.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2020-05-23T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[{\"id\":\"some-id\",\"description\":\"description\",\"amount\":\"123.00\",\"plan\":\"some-plan\",\"planName\":\"Plan with id: some-plan\",\"cpu\":{},\"memory\":{},\"disk\":{}}]}");
+ tester.assertResponse(singleRequest, "{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-28\",\"total\":\"123.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2020-05-23T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[{\"id\":\"some-id\",\"description\":\"description\",\"amount\":\"123.00\",\"plan\":\"some-plan\",\"planName\":\"Plan with id: some-plan\",\"cpu\":{},\"memory\":{},\"disk\":{}}]}");
}
@Test
@@ -126,7 +127,7 @@ public class BillingApiHandlerV2Test extends ControllerContainerCloudTest {
@Test
public void require_accountant_tenant_preview() {
var accountantRequest = request("/billing/v2/accountant/preview/tenant/tenant1").roles(Role.hostedAccountant());
- tester.assertResponse(accountantRequest, "{\"id\":\"empty\",\"from\":\"2021-04-13\",\"to\":\"2021-04-13\",\"total\":\"0.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2021-04-13T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[]}");
+ tester.assertResponse(accountantRequest, "{\"id\":\"empty\",\"from\":\"2021-04-13\",\"to\":\"2021-04-12\",\"total\":\"0.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2021-04-13T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[]}");
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view
index c0deca3d671..e5588c45677 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view
@@ -21,7 +21,8 @@
{
"id":"id-1",
"from":"2020-05-23",
- "to":"2020-05-28","amount":"123.00",
+ "to":"2020-05-28",
+ "amount":"123.00",
"status":"OPEN",
"statusHistory":[
{