diff options
author | Ola Aunrønning <olaa@verizonmedia.com> | 2020-06-29 10:26:28 +0200 |
---|---|---|
committer | Ola Aunrønning <olaa@verizonmedia.com> | 2020-06-29 10:26:28 +0200 |
commit | 71e6628cf3aaa58d8a4dfd8325da5f3e841866a2 (patch) | |
tree | 149ad36bf5300bdd96d3f90b239b1e1691c99d19 /controller-api | |
parent | 0dbbd3c3be2870681480e73f9cc491e349b06610 (diff) |
Revert "Merge pull request #13726 from vespa-engine/revert-13715-olaa/billing-api-handler"
This reverts commit 0dbbd3c3be2870681480e73f9cc491e349b06610, reversing
changes made to 0a8b5894dfc442d661836fce4ddb6c870bcc0ec0.
Diffstat (limited to 'controller-api')
15 files changed, 671 insertions, 108 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java index 0b5f2538892..a522e26a46d 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java @@ -4,7 +4,7 @@ package com.yahoo.vespa.hosted.controller.api.integration; import com.yahoo.vespa.hosted.controller.api.integration.aws.ApplicationRoleService; import com.yahoo.vespa.hosted.controller.api.integration.aws.AwsEventFetcher; import com.yahoo.vespa.hosted.controller.api.integration.aws.ResourceTagger; -import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanController; +import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController; import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateProvider; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServer; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore; @@ -77,6 +77,6 @@ public interface ServiceRegistry { SystemMonitor systemMonitor(); - PlanController planController(); + BillingController billingController(); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java new file mode 100644 index 00000000000..bd9568fe891 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java @@ -0,0 +1,49 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public interface BillingController { + + PlanId getPlan(TenantName tenant); + + /** + * Returns true if plan was changed + */ + boolean setPlan(TenantName tenant, PlanId planId, boolean hasApplications); + + Invoice.Id createInvoiceForPeriod(TenantName tenant, ZonedDateTime startTime, ZonedDateTime endTime, String agent); + + Invoice createUncommittedInvoice(TenantName tenant, LocalDate until); + + Map<TenantName, Invoice> createUncommittedInvoices(LocalDate until); + + List<Invoice.LineItem> getUnusedLineItems(TenantName tenant); + + Optional<PaymentInstrument> getDefaultInstrument(TenantName tenant); + + String createClientToken(String tenant, String userId); + + boolean deleteInstrument(TenantName tenant, String userId, String instrumentId); + + void updateInvoiceStatus(Invoice.Id invoiceId, String agent, String status); + + void addLineItem(TenantName tenant, String description, BigDecimal amount, String agent); + + void deleteLineItem(String lineItemId); + + boolean setActivePaymentInstrument(InstrumentOwner paymentInstrument); + + InstrumentList listInstruments(TenantName tenant, String userId); + + List<Invoice> getInvoices(TenantName tenant); + +}
\ No newline at end of file diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/CostCalculator.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/CostCalculator.java deleted file mode 100644 index 628beec8450..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/CostCalculator.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.integration.billing; - -import com.yahoo.config.provision.NodeResources; -import com.yahoo.vespa.hosted.controller.api.integration.resource.CostInfo; - - -/** - * @author ogronnesby - */ -public interface CostCalculator { - - /** Calculate the cost for the given usage */ - CostInfo calculate(ResourceUsage usage); - - /** Estimate the cost for the given resources */ - double calculate(NodeResources resources); - -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentList.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentList.java new file mode 100644 index 00000000000..f26261cd157 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentList.java @@ -0,0 +1,39 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author olaa + */ +public class InstrumentList { + + private String activeInstrumentId; + private List<PaymentInstrument> instruments; + + + public InstrumentList(List<PaymentInstrument> instruments) { + this.instruments = instruments; + } + + public void setActiveInstrumentId(String activeInstrumentId) { + this.activeInstrumentId = activeInstrumentId; + } + + public void addInstrument(PaymentInstrument instrument) { + instruments.add(instrument); + } + + public void addInstruments(List<PaymentInstrument> instruments) { + instruments.addAll(instruments); + } + + public String getActiveInstrumentId() { + return activeInstrumentId; + } + + public List<PaymentInstrument> getInstruments() { + return instruments; + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentOwner.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentOwner.java new file mode 100644 index 00000000000..45e06b11b2a --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/InstrumentOwner.java @@ -0,0 +1,67 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import com.yahoo.config.provision.TenantName; + +import java.util.Objects; + +/** + * @author olaa + */ +public class InstrumentOwner { + + private final TenantName tenantName; + private final String userId; + private final String paymentInstrumentId; + private final boolean isDefault; + + public InstrumentOwner(TenantName tenantName, String userId, String paymentInstrumentId, boolean isDefault) { + this.tenantName = tenantName; + this.userId = userId; + this.paymentInstrumentId = paymentInstrumentId; + this.isDefault = isDefault; + } + + public TenantName getTenantName() { + return tenantName; + } + + public String getUserId() { + return userId; + } + + public String getPaymentInstrumentId() { + return paymentInstrumentId; + } + + public boolean isDefault() { + return isDefault; + } + + @Override + public String toString() { + return String.format( + "Tenant: %s\nCusomer ID: %s\nPayment Instrument ID: %s\nIs default: %s", + tenantName.value(), + userId, + paymentInstrumentId, + isDefault + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InstrumentOwner other = (InstrumentOwner) o; + return this.tenantName.equals(other.getTenantName()) && + this.userId.equals(other.getUserId()) && + this.paymentInstrumentId.equals(other.getPaymentInstrumentId()) && + this.isDefault() == other.isDefault(); + } + + @Override + public int hashCode() { + return Objects.hash(tenantName, userId, paymentInstrumentId, isDefault); + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java new file mode 100644 index 00000000000..31388d24e2e --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Invoice.java @@ -0,0 +1,266 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.zone.ZoneId; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.UUID; + + +/** + * An Invoice is an identifier with a status (with history) and line items. A line item is the meat and + * potatoes of the content of the invoice, and are a history of items. Most line items are connected to + * a given deployment in Vespa Cloud, but they can also be manually added to e.g. give a discount or represent + * support. + * <p> + * All line items have a Plan associated with them - which was used to map from utilization to an actual price. + * <p> + * The invoice has a status history, but only the latest status is exposed through this API. + * + * @author ogronnesby + */ +public class Invoice { + private static final BigDecimal SCALED_ZERO = new BigDecimal("0.00"); + + private final Id id; + private final List<LineItem> lineItems; + private final StatusHistory statusHistory; + private final ZonedDateTime startTime; + private final ZonedDateTime endTime; + + public Invoice(Id id, StatusHistory statusHistory, List<LineItem> lineItems, ZonedDateTime startTime, ZonedDateTime endTime) { + this.id = id; + this.lineItems = List.copyOf(lineItems); + this.statusHistory = statusHistory; + this.startTime = startTime; + this.endTime = endTime; + } + + public Id id() { + return id; + } + + public String status() { + return statusHistory.current(); + } + + public StatusHistory statusHistory() { + return statusHistory; + } + + public List<LineItem> lineItems() { + return lineItems; + } + + public ZonedDateTime getStartTime() { + return startTime; + } + + public ZonedDateTime getEndTime() { + return endTime; + } + + public BigDecimal sum() { + return lineItems.stream().map(LineItem::amount).reduce(SCALED_ZERO, BigDecimal::add); + } + + public static final class Id { + private final String value; + + public static Id of(String value) { + Objects.requireNonNull(value); + return new Id(value); + } + + public static Id generate() { + var id = UUID.randomUUID().toString(); + return new Id(id); + } + + private Id(String value) { + this.value = value; + } + + public String value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Id invoiceId = (Id) o; + return value.equals(invoiceId.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "InvoiceId{" + + "value='" + value + '\'' + + '}'; + } + } + + /** + * Represents a chargeable line on an invoice. + */ + public static class LineItem { + private final String id; + private final String description; + private final BigDecimal amount; + private final String plan; + private final String agent; + private final ZonedDateTime addedAt; + private final Optional<ZonedDateTime> startedAt; + private final Optional<ZonedDateTime> endedAt; + private final Optional<ApplicationId> applicationId; + private final Optional<ZoneId> zoneId; + + public LineItem(String id, String description, BigDecimal amount, String plan, String agent, ZonedDateTime addedAt, ZonedDateTime startedAt, ZonedDateTime endedAt, ApplicationId applicationId, ZoneId zoneId) { + this.id = id; + this.description = description; + this.amount = amount; + this.plan = plan; + this.agent = agent; + this.addedAt = addedAt; + this.startedAt = Optional.ofNullable(startedAt); + this.endedAt = Optional.ofNullable(endedAt); + + if (applicationId == null && zoneId != null) + throw new IllegalArgumentException("Must supply applicationId if zoneId is supplied"); + + this.applicationId = Optional.ofNullable(applicationId); + this.zoneId = Optional.ofNullable(zoneId); + } + + public LineItem(String id, String description, BigDecimal amount, String plan, String agent, ZonedDateTime addedAt) { + this(id, description, amount, plan, agent, addedAt, null, null, null, null); + } + + /** The opaque ID of this */ + public String id() { + return id; + } + + /** The string description of this - used for display purposes */ + public String description() { + return description; + } + + /** The dollar amount of this */ + public BigDecimal amount() { + return SCALED_ZERO.add(amount); + } + + /** The plan used to calculate amount of this */ + public String plan() { + return plan; + } + + /** Who created this line item */ + public String agent() { + return agent; + } + + /** When was this line item added */ + public ZonedDateTime addedAt() { + return addedAt; + } + + /** What time period is this line item for - time start */ + public Optional<ZonedDateTime> startedAt() { + return startedAt; + } + + /** What time period is this line item for - time end */ + public Optional<ZonedDateTime> endedAt() { + return endedAt; + } + + /** Optionally - what application is this line item about */ + public Optional<ApplicationId> applicationId() { + return applicationId; + } + + /** Optionally - what zone deployment is this line item about */ + public Optional<ZoneId> zoneId() { + return zoneId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LineItem lineItem = (LineItem) o; + return id.equals(lineItem.id) && + description.equals(lineItem.description) && + amount.equals(lineItem.amount) && + plan.equals(lineItem.plan) && + agent.equals(lineItem.agent) && + addedAt.equals(lineItem.addedAt) && + startedAt.equals(lineItem.startedAt) && + endedAt.equals(lineItem.endedAt) && + applicationId.equals(lineItem.applicationId) && + zoneId.equals(lineItem.zoneId); + } + + @Override + public int hashCode() { + return Objects.hash(id, description, amount, plan, agent, addedAt, startedAt, endedAt, applicationId, zoneId); + } + + @Override + public String toString() { + return "LineItem{" + + "id='" + id + '\'' + + ", description='" + description + '\'' + + ", amount=" + amount + + ", plan='" + plan + '\'' + + ", agent='" + agent + '\'' + + ", addedAt=" + addedAt + + ", startedAt=" + startedAt + + ", endedAt=" + endedAt + + ", applicationId=" + applicationId + + ", zoneId=" + zoneId + + '}'; + } + } + + public static class StatusHistory { + SortedMap<ZonedDateTime, String> history; + + public StatusHistory(SortedMap<ZonedDateTime, String> history) { + this.history = history; + } + + public static StatusHistory open() { + return new StatusHistory( + new TreeMap<>(Map.of(ZonedDateTime.now(), "OPEN")) + ); + } + + public String current() { + return history.get(history.lastKey()); + } + + public SortedMap<ZonedDateTime, String> getHistory() { + return history; + } + + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java new file mode 100644 index 00000000000..a4c25e301ba --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java @@ -0,0 +1,144 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @author olaa + */ +public class MockBillingController implements BillingController { + + Map<TenantName, PlanId> plans = new HashMap<>(); + Map<TenantName, PaymentInstrument> activeInstruments = new HashMap<>(); + Map<TenantName, List<Invoice>> committedInvoices = new HashMap<>(); + Map<TenantName, Invoice> uncommittedInvoices = new HashMap<>(); + Map<TenantName, List<Invoice.LineItem>> unusedLineItems = new HashMap<>(); + + @Override + public PlanId getPlan(TenantName tenant) { + return plans.get(tenant); + } + + @Override + public boolean setPlan(TenantName tenant, PlanId planId, boolean hasApplications) { + plans.put(tenant, planId); + return true; + } + + @Override + public Invoice.Id createInvoiceForPeriod(TenantName tenant, ZonedDateTime startTime, ZonedDateTime endTime, String agent) { + var invoiceId = Invoice.Id.of("id-123"); + committedInvoices.computeIfAbsent(tenant, l -> new ArrayList<>()) + .add(new Invoice( + invoiceId, + Invoice.StatusHistory.open(), + List.of(), + startTime, + endTime + )); + return invoiceId; + } + + @Override + public Invoice createUncommittedInvoice(TenantName tenant, LocalDate until) { + return uncommittedInvoices.get(tenant); + } + + @Override + public Map<TenantName, Invoice> createUncommittedInvoices(LocalDate until) { + return uncommittedInvoices; + } + + @Override + public List<Invoice.LineItem> getUnusedLineItems(TenantName tenant) { + return unusedLineItems.getOrDefault(tenant, List.of()); + } + + @Override + public Optional<PaymentInstrument> getDefaultInstrument(TenantName tenant) { + return Optional.ofNullable(activeInstruments.get(tenant)); + } + + @Override + public String createClientToken(String tenant, String userId) { + return "some-token"; + } + + @Override + public boolean deleteInstrument(TenantName tenant, String userId, String instrumentId) { + activeInstruments.remove(tenant); + return true; + } + + @Override + public void updateInvoiceStatus(Invoice.Id invoiceId, String agent, String status) { + committedInvoices.values().stream() + .flatMap(List::stream) + .filter(invoice -> invoiceId.equals(invoice.id())) + .forEach(invoice -> invoice.statusHistory().history.put(ZonedDateTime.now(), status)); + } + + @Override + public void addLineItem(TenantName tenant, String description, BigDecimal amount, String agent) { + unusedLineItems.computeIfAbsent(tenant, l -> new ArrayList<>()) + .add(new Invoice.LineItem( + "line-item-id", + description, + amount, + "some-plan", + agent, + ZonedDateTime.now() + )); + } + + @Override + public void deleteLineItem(String lineItemId) { + + } + + @Override + public boolean setActivePaymentInstrument(InstrumentOwner paymentInstrument) { + var instrumentId = paymentInstrument.getPaymentInstrumentId(); + activeInstruments.put(paymentInstrument.getTenantName(), createInstrument(instrumentId)); + return true; + } + + @Override + public InstrumentList listInstruments(TenantName tenant, String userId) { + return null; + } + + @Override + public List<Invoice> getInvoices(TenantName tenant) { + return committedInvoices.getOrDefault(tenant, List.of()); + } + + private PaymentInstrument createInstrument(String id) { + return new PaymentInstrument(id, + "name", + "displayText", + "brand", + "type", + "endingWith", + "expiryDate" + ); + } + + public void addInvoice(TenantName tenantName, Invoice invoice, boolean committed) { + if (committed) + committedInvoices.computeIfAbsent(tenantName, i -> new ArrayList<>()) + .add(invoice); + else + uncommittedInvoices.put(tenantName, invoice); + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PaymentInstrument.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PaymentInstrument.java new file mode 100644 index 00000000000..7b8d36f3d4f --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PaymentInstrument.java @@ -0,0 +1,51 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +/** + * @author olaa + */ +public class PaymentInstrument { + + private final String id; + private final String nameOnCard; + private final String displayText; + private final String brand; + private final String type; + private final String endingWith; + private final String expiryDate; + + + public PaymentInstrument(String id, String nameOnCard, String displayText, String brand, String type, String endingWith, String expiryDate) { + this.id = id; + this.nameOnCard = nameOnCard; + this.displayText = displayText; + this.brand = brand; + this.type = type; + this.endingWith = endingWith; + this.expiryDate = expiryDate; + } + + public String getId() { + return id; + } + + public String getNameOnCard() { + return nameOnCard; + } + + public String getDisplayText() { + return displayText; + } + + public String getBrand() { + return brand; + } + + public String getType() { + return type; + } + + public String getEndingWith() { + return endingWith; + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Plan.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Plan.java deleted file mode 100644 index 75a88136c45..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Plan.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.integration.billing; - -/** - * A Plan decides two different things: - * - * - How to map from usage to a sum of money that is owed. - * - Limits on how much resources can be used. - * - * @author ogronnesby - */ -public interface Plan { - - /** The ID of the plan as used in APIs and storage systems */ - String id(); - - /** The calculator used to calculate a bill for usage */ - CostCalculator calculator(); - - /** The quota limits associated with the plan */ - Object quota(); - -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanController.java deleted file mode 100644 index f13c251d212..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanController.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.integration.billing; - -import com.yahoo.config.provision.TenantName; - -public interface PlanController { - - Plan getPlan(TenantName tenant); - -}
\ No newline at end of file diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanId.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanId.java new file mode 100644 index 00000000000..68a897c904f --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanId.java @@ -0,0 +1,43 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.billing; + +import java.util.Objects; + +/** + * @author olaa + */ +public class PlanId { + + private final String value; + + public PlanId(String value) { + if (value.isBlank()) + throw new IllegalArgumentException("Id must be non-blank."); + this.value = value; + } + + public static PlanId from(String value) { + return new PlanId(value); + } + + public String value() { return value; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlanId id = (PlanId) o; + return Objects.equals(value, id.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "plan '" + value + "'"; + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/ResourceUsage.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/ResourceUsage.java deleted file mode 100644 index cbfd2b6ff50..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/ResourceUsage.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.integration.billing; - -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.zone.ZoneId; - -import java.math.BigDecimal; - -/** - * @author olaa - */ -public class ResourceUsage { - - private final ApplicationId applicationId; - private final ZoneId zoneId; - private final Plan plan; - private final BigDecimal cpuMillis; - private final BigDecimal memoryMillis; - private final BigDecimal diskMillis; - - public ResourceUsage(ApplicationId applicationId, ZoneId zoneId, Plan plan, - BigDecimal cpuMillis, BigDecimal memoryMillis, BigDecimal diskMillis) { - this.applicationId = applicationId; - this.zoneId = zoneId; - this.cpuMillis = cpuMillis; - this.memoryMillis = memoryMillis; - this.diskMillis = diskMillis; - this.plan = plan; - } - - public ApplicationId getApplicationId() { - return applicationId; - } - - public ZoneId getZoneId() { - return zoneId; - } - - public BigDecimal getCpuMillis() { - return cpuMillis; - } - - public BigDecimal getMemoryMillis() { - return memoryMillis; - } - - public BigDecimal getDiskMillis() { - return diskMillis; - } - - public Plan getPlan() { - return plan; - } -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java index 2fdf442dbe0..aaddd3811bc 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java @@ -72,6 +72,10 @@ enum PathGroup { PathPrefix.api, "/billing/v1/tenant/{tenant}/instrument/{*}"), + billingPlan(Matcher.tenant, + PathPrefix.api, + "/billing/v1/tenant/{tenant}/plan/{*}"), + billingList(Matcher.tenant, PathPrefix.api, "/billing/v1/tenant/{tenant}/billing/{*}"), diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java index 83adba6f59b..548ad0af484 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java @@ -158,6 +158,11 @@ enum Policy { .on(PathGroup.billingToken) .in(SystemName.PublicCd)), + /** Ability to update tenant payment instrument */ + planUpdate(Privilege.grant(Action.update) + .on(PathGroup.billingPlan) + .in(SystemName.PublicCd)), + /** Read the generated bills */ billingInformationRead(Privilege.grant(Action.read) .on(PathGroup.billingList) diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java index b9d534019db..801661f454e 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java @@ -67,6 +67,7 @@ public enum RoleDefinition { Policy.paymentInstrumentUpdate, Policy.paymentInstrumentDelete, Policy.paymentInstrumentCreate, + Policy.planUpdate, Policy.billingInformationRead), /** Headless — the application specific role identified by deployment keys for production */ |