aboutsummaryrefslogtreecommitdiffstats
path: root/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/PlanRegistryMock.java
blob: 5af4d0cff292b87a25c35382fc3fd09cfcddea77 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright Vespa.ai. 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;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceUsage;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class PlanRegistryMock implements PlanRegistry {

    public static final Plan freeTrial = new MockPlan("trial", false, false, 0, 0, 0, 0, 200, "Free Trial - for testing purposes");
    public static final Plan paidPlan  = new MockPlan("paid", true, true, "0.09", "0.009", "0.0003", "0.075", 500, "Paid Plan - for testing purposes");
    public static final Plan nonePlan  = new MockPlan("none", false, false, 0, 0, 0, 0, 0, "None Plan - for testing purposes");

    @Override
    public Plan defaultPlan() {
        return freeTrial;
    }

    @Override
    public Optional<Plan> plan(PlanId planId) {
        return Stream.of(freeTrial, paidPlan, nonePlan)
                .filter(p -> p.id().equals(planId))
                .findAny();
    }

    @Override
    public List<Plan> all() {
        return List.of(freeTrial, paidPlan, nonePlan);
    }

    private static class MockPlan implements Plan {
        private final PlanId planId;
        private final String description;
        private final CostCalculator costCalculator;
        private final QuotaCalculator quotaCalculator;
        private final boolean billed;
        private final boolean supported;

        public MockPlan(String planId, boolean billed, boolean supported, double cpuPrice, double memPrice, double dgbPrice, double gpuPrice, int quota, String description) {
            this(PlanId.from(planId), billed, supported, new MockCostCalculator(cpuPrice, memPrice, dgbPrice, gpuPrice), () -> createQuota(quota), description);
        }

        public MockPlan(String planId, boolean billed, boolean supported, String cpuPrice, String memPrice, String dgbPrice, String gpuPrice, int quota, String description) {
            this(PlanId.from(planId), billed, supported, new MockCostCalculator(cpuPrice, memPrice, dgbPrice, gpuPrice), () -> createQuota(quota), description);
        }

        private static Quota createQuota(int quota) {
            return quota == 0 ? Quota.zero() : Quota.unlimited().withBudget(quota);
        }
        
        public MockPlan(PlanId planId, boolean billed, boolean supported, MockCostCalculator calculator, QuotaCalculator quota, String description) {
            this.planId = planId;
            this.billed = billed;
            this.supported = supported;
            this.costCalculator = calculator;
            this.quotaCalculator = quota;
            this.description = description;
        }

        @Override
        public PlanId id() {
            return planId;
        }

        @Override
        public String displayName() {
            return description;
        }

        @Override
        public CostCalculator calculator() {
            return costCalculator;
        }

        @Override
        public QuotaCalculator quota() {
            return quotaCalculator;
        }

        @Override
        public boolean isBilled() {
            return billed;
        }

        @Override
        public boolean isSupported() {
            return supported;
        }
    }

    private static class MockCostCalculator implements CostCalculator {
        private static final BigDecimal millisPerHour = BigDecimal.valueOf(60 * 60 * 1000);
        private final BigDecimal cpuHourCost;
        private final BigDecimal memHourCost;
        private final BigDecimal dgbHourCost;
        private final BigDecimal gpuHourCost;

        public MockCostCalculator(String cpuPrice, String memPrice, String dgbPrice, String gpuPrice) {
            this(new BigDecimal(cpuPrice), new BigDecimal(memPrice), new BigDecimal(dgbPrice), new BigDecimal(gpuPrice));
        }

        public MockCostCalculator(double cpuPrice, double memPrice, double dgbPrice, double gpuPrice) {
            this(BigDecimal.valueOf(cpuPrice), BigDecimal.valueOf(memPrice), BigDecimal.valueOf(dgbPrice), BigDecimal.valueOf(gpuPrice));
        }

        public MockCostCalculator(BigDecimal cpuPrice, BigDecimal memPrice, BigDecimal dgbPrice, BigDecimal gpuPrice) {
            this.cpuHourCost = cpuPrice;
            this.memHourCost = memPrice;
            this.dgbHourCost = dgbPrice;
            this.gpuHourCost = gpuPrice;
        }

        @Override
        public CostInfo calculate(ResourceUsage usage) {
            var cpuCost = usage.getCpuMillis().multiply(cpuHourCost).divide(millisPerHour, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
            var memCost = usage.getMemoryMillis().multiply(memHourCost).divide(millisPerHour, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
            var dgbCost = usage.getDiskMillis().multiply(dgbHourCost).divide(millisPerHour, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
            var gpuCost = usage.getGpuMillis().multiply(gpuHourCost).divide(millisPerHour, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);

            return new CostInfo(
                    usage.getApplicationId(),
                    usage.getZoneId(),
                    usage.getCpuMillis().divide(millisPerHour, RoundingMode.HALF_UP),
                    usage.getMemoryMillis().divide(millisPerHour, RoundingMode.HALF_UP),
                    usage.getDiskMillis().divide(millisPerHour, RoundingMode.HALF_UP),
                    usage.getGpuMillis().divide(millisPerHour, RoundingMode.HALF_UP),
                    cpuCost,
                    memCost,
                    dgbCost,
                    gpuCost,
                    usage.getArchitecture(),
                    usage.getMajorVersion(),
                    usage.getCloudAccount()
            );
        }

        @Override
        public double calculate(NodeResources resources) {
            return resources.cost();
        }

        @Override
        public BigDecimal getCpuPrice() {
            return cpuHourCost;
        }

        @Override
        public BigDecimal getMemoryPrice() {
            return memHourCost;
        }

        @Override
        public BigDecimal getDiskPrice() {
            return dgbHourCost;
        }

        @Override
        public BigDecimal getGpuPrice() {
            return gpuHourCost;
        }
    }
}