summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java15
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java2
10 files changed, 51 insertions, 14 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java
index 8765884e23c..d482dedfdaa 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java
@@ -113,7 +113,7 @@ public class CloudTrialExpirer extends ControllerMaintainer {
private void setPlanNone(List<Tenant> tenants) {
tenants.forEach(tenant -> {
- controller().serviceRegistry().billingController().setPlan(tenant.name(), PlanId.from("none"), false);
+ controller().serviceRegistry().billingController().setPlan(tenant.name(), PlanId.from("none"), false, false);
});
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
index d0b3b9f4c7f..1463cce595d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
@@ -44,7 +44,7 @@ import java.util.stream.Stream;
public class VcmrMaintainer extends ControllerMaintainer {
private static final Logger LOG = Logger.getLogger(VcmrMaintainer.class.getName());
- private static final Duration ALLOWED_RETIREMENT_TIME = Duration.ofHours(60);
+ private static final int DAYS_TO_RETIRE = 2;
private static final Duration ALLOWED_POSTPONEMENT_TIME = Duration.ofDays(7);
private final CuratorDb curator;
@@ -240,8 +240,7 @@ public class VcmrMaintainer extends ControllerMaintainer {
private boolean shouldRetire(VespaChangeRequest changeRequest, HostAction action) {
return action.getState() == State.PENDING_RETIREMENT &&
- changeRequest.getChangeRequestSource().getPlannedStartTime()
- .minus(ALLOWED_RETIREMENT_TIME)
+ getRetirementStartTime(changeRequest.getChangeRequestSource().getPlannedStartTime())
.isBefore(ZonedDateTime.now());
}
@@ -337,4 +336,16 @@ public class VcmrMaintainer extends ControllerMaintainer {
nodeRepository.updateReports(zoneId, node.hostname().value(), report.toNodeReports());
}
+ // Calculate wanted retirement start time, ignoring weekends
+ // protected for testing
+ protected ZonedDateTime getRetirementStartTime(ZonedDateTime plannedStartTime) {
+ var time = plannedStartTime;
+ var days = 0;
+ while (days < DAYS_TO_RETIRE) {
+ time = time.minusDays(1);
+ if (time.getDayOfWeek().getValue() < 6) days++;
+ }
+ return time;
+ }
+
}
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 33307ea1677..3f610d27950 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
@@ -24,6 +24,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.billing.CollectionMetho
import com.yahoo.vespa.hosted.controller.api.integration.billing.InstrumentOwner;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PaymentInstrument;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
+import com.yahoo.vespa.hosted.controller.api.role.Role;
+import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.yolean.Exceptions;
@@ -41,6 +43,7 @@ import java.time.format.DateTimeParseException;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -158,9 +161,11 @@ public class BillingApiHandler extends ThreadedHttpRequestHandler {
var tenantName = TenantName.from(tenant);
var slime = inspectorOrThrow(request);
var planId = PlanId.from(slime.field("plan").asString());
+ var roles = requestRoles(request);
+ var isAccountant = roles.contains(Role.hostedAccountant());
var hasDeployments = hasDeployments(tenantName);
- var result = billingController.setPlan(tenantName, planId, hasDeployments);
+ var result = billingController.setPlan(tenantName, planId, hasDeployments, isAccountant);
if (result.isSuccess())
return new StringResponse("Plan: " + planId.value());
@@ -483,4 +488,12 @@ public class BillingApiHandler extends ThreadedHttpRequestHandler {
.count() > 0;
}
+ private static Set<Role> requestRoles(HttpRequest request) {
+ return Optional.ofNullable(request.getJDiscRequest().context().get(SecurityContext.ATTRIBUTE_NAME))
+ .filter(SecurityContext.class::isInstance)
+ .map(SecurityContext.class::cast)
+ .map(SecurityContext::roles)
+ .orElseThrow(() -> new IllegalArgumentException("Attribute '" + SecurityContext.ATTRIBUTE_NAME + "' was not set on request"));
+ }
+
}
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 0f3e5b7f76b..087d6152afc 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
@@ -110,7 +110,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
if (newPlan.valid() && newPlan.type() == Type.STRING) {
var planId = PlanId.from(newPlan.asString());
var hasDeployments = tenantHasDeployments(tenant.name());
- var result = billing.setPlan(tenant.name(), planId, hasDeployments);
+ var result = billing.setPlan(tenant.name(), planId, hasDeployments, false);
if (! result.isSuccess()) {
throw new RestApiException.Forbidden(result.getErrorMessage().get());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java
index f768ab5e61b..2e34c6511a7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirerTest.java
@@ -86,7 +86,7 @@ public class CloudTrialExpirerTest {
private void registerTenant(String tenantName, String plan, Duration timeSinceLastLogin) {
var name = TenantName.from(tenantName);
tester.createTenant(tenantName, Tenant.Type.cloud);
- tester.serviceRegistry().billingController().setPlan(name, PlanId.from(plan), false);
+ tester.serviceRegistry().billingController().setPlan(name, PlanId.from(plan), false, false);
tester.controller().tenants().updateLastLogin(name, List.of(LastLoginInfo.UserLevel.user), tester.controller().clock().instant().minus(timeSinceLastLogin));
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
index 64e3a95605a..215c03030a9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
@@ -490,8 +490,8 @@ public class MetricsReporterTest {
tester.createTenant("foo", Tenant.Type.cloud);
tester.createTenant("bar", Tenant.Type.cloud);
tester.createTenant("fix", Tenant.Type.cloud);
- tester.controller().serviceRegistry().billingController().setPlan(TenantName.from("foo"), PlanId.from("pay-as-you-go"), false);
- tester.controller().serviceRegistry().billingController().setPlan(TenantName.from("bar"), PlanId.from("pay-as-you-go"), false);
+ tester.controller().serviceRegistry().billingController().setPlan(TenantName.from("foo"), PlanId.from("pay-as-you-go"), false, false);
+ tester.controller().serviceRegistry().billingController().setPlan(TenantName.from("bar"), PlanId.from("pay-as-you-go"), false, false);
var reporter = createReporter(tester.controller());
reporter.maintain();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java
index e7a6c3ea3c3..bfbd3836ce7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainerTest.java
@@ -18,9 +18,11 @@ import com.yahoo.vespa.hosted.controller.integration.NodeRepositoryMock;
import org.junit.Before;
import org.junit.Test;
+import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
+import java.time.temporal.TemporalAdjusters;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -244,6 +246,17 @@ public class VcmrMaintainerTest {
assertEquals(Status.OUT_OF_SYNC, writtenChangeRequest.getStatus());
}
+ @Test
+ public void retirement_start_time_ignores_weekends() {
+ var plannedStartTime = ZonedDateTime.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.WEDNESDAY));
+ var retirementStartTime = maintainer.getRetirementStartTime(plannedStartTime);
+ assertEquals(plannedStartTime.minusDays(2), retirementStartTime);
+
+ plannedStartTime = ZonedDateTime.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY));
+ retirementStartTime = maintainer.getRetirementStartTime(plannedStartTime);
+ assertEquals(plannedStartTime.minusDays(4), retirementStartTime);
+ }
+
private VespaChangeRequest canceledChangeRequest() {
return newChangeRequest(ChangeRequestSource.Status.CANCELED, State.RETIRED, State.RETIRING, ZonedDateTime.now());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index 33b7500ceac..5368cc73480 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -211,7 +211,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
@Test
public void trial_tenant_limit_reached() {
((InMemoryFlagSource) tester.controller().flagSource()).withIntFlag(PermanentFlags.MAX_TRIAL_TENANTS.id(), 1);
- tester.controller().serviceRegistry().billingController().setPlan(tenantName, PlanId.from("pay-as-you-go"), false);
+ tester.controller().serviceRegistry().billingController().setPlan(tenantName, PlanId.from("pay-as-you-go"), false, false);
// tests that we can create the one trial tenant the flag says we can have -- and that the tenant created
// in @Before does not count towards that limit.
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 0ef242aed16..b58e5294f66 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
@@ -102,7 +102,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
billingController.addBill(tenant, bill, true);
billingController.addBill(tenant, bill, false);
- billingController.setPlan(tenant, PlanId.from("some-plan"), true);
+ billingController.setPlan(tenant, PlanId.from("some-plan"), true, false);
var request = request("/billing/v1/tenant/tenant1/billing?until=2020-05-28").roles(tenantRole);
tester.assertResponse(request, new File("tenant-billing-view.json"));
@@ -179,8 +179,8 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
tester.controller().tenants().create(new CloudTenantSpec(tenant2, ""), new Auth0Credentials(() -> "foo", Set.of(Role.hostedOperator())));
var bill = createBill();
- billingController.setPlan(tenant, PlanId.from("some-plan"), true);
- billingController.setPlan(tenant2, PlanId.from("some-plan"), true);
+ billingController.setPlan(tenant, PlanId.from("some-plan"), true, false);
+ billingController.setPlan(tenant2, PlanId.from("some-plan"), true, false);
billingController.addBill(tenant, bill, false);
billingController.addLineItem(tenant, "support", new BigDecimal("42"), "Smith");
billingController.addBill(tenant2, bill, false);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
index d0c95fe593e..1bb409b9906 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
@@ -291,7 +291,7 @@ public class UserApiTest extends ControllerContainerCloudTest {
var tenant1 = controller.createTenant("tenant1", Tenant.Type.cloud);
var tenant2 = controller.createTenant("tenant2", Tenant.Type.cloud);
- controller.serviceRegistry().billingController().setPlan(tenant2, PlanId.from("paid"), false);
+ controller.serviceRegistry().billingController().setPlan(tenant2, PlanId.from("paid"), false, false);
tester.assertResponse(
request("/user/v1/user")