diff options
Diffstat (limited to 'controller-server')
6 files changed, 76 insertions, 5 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java index bf2f2ab90eb..d11540b28dd 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java @@ -12,6 +12,7 @@ import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.security.AccessControl; import com.yahoo.vespa.hosted.controller.security.Credentials; import com.yahoo.vespa.hosted.controller.security.TenantSpec; +import com.yahoo.vespa.hosted.controller.tenant.CloudAccountInfo; import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; import com.yahoo.vespa.hosted.controller.tenant.Tenant; @@ -165,6 +166,14 @@ public class TenantController { } } + public void updateCloudAccounts(TenantName tenantName, List<CloudAccountInfo> cloudAccounts) { + try (Mutex lock = lock(tenantName)) { + var tenant = require(tenantName); + if (tenant.cloudAccounts().equals(cloudAccounts)) return; // no change + curator.writeTenant(LockedTenant.of(tenant, lock).withCloudAccounts(cloudAccounts).get()); + } + } + /** Deletes the given tenant. */ public void delete(TenantName tenant, Optional<Credentials> credentials, boolean forget) { try (Mutex lock = lock(tenant)) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudAccountVerifier.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudAccountVerifier.java new file mode 100644 index 00000000000..f0fc8985bdf --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudAccountVerifier.java @@ -0,0 +1,55 @@ +package com.yahoo.vespa.hosted.controller.maintenance; + +import com.yahoo.config.provision.SystemName; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.tenant.CloudAccountInfo; +import com.yahoo.vespa.hosted.controller.tenant.Tenant; + +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +import static java.util.logging.Level.WARNING; + +/** + * Verifies the cloud accounts that may be used by a given user have applied the enclave template + * and extracts the version of the applied template. + * + * All maintainers that operate on external cloud accounts should use the list on the Tenant instance + * maintained by this class rather than the cloud-accounts feature flag. + * + * The template version can be used to determine if new features can be enabled for the cloud account. + * + * @author freva + */ +public class CloudAccountVerifier extends ControllerMaintainer { + + private static final Logger logger = Logger.getLogger(CloudAccountVerifier.class.getName()); + + CloudAccountVerifier(Controller controller, Duration interval) { + super(controller, interval, null, Set.of(SystemName.PublicCd, SystemName.Public)); + } + + @Override + protected double maintain() { + int attempts = 0, failures = 0; + for (Tenant tenant : controller().tenants().asList()) { + try { + attempts++; + List<CloudAccountInfo> cloudAccountInfos = controller().applications().accountsOf(tenant.name()).stream() + .flatMap(account -> controller().serviceRegistry() + .archiveService() + .getEnclaveTemplateVersion(account) + .map(version -> new CloudAccountInfo(account, version)) + .stream()) + .toList(); + controller().tenants().updateCloudAccounts(tenant.name(), cloudAccountInfos); + } catch (RuntimeException e) { + logger.log(WARNING, "Failed to verify cloud accounts for tenant " + tenant.name(), e); + failures++; + } + } + return asSuccessFactorDeviation(attempts, failures); + } +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 6fae732df0a..3dcd8457da6 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -85,6 +85,7 @@ public class ControllerMaintenance extends AbstractComponent { maintainers.add(new EnclaveAccessMaintainer(controller, intervals.defaultInterval)); maintainers.add(new CertificatePoolMaintainer(controller, metric, intervals.certificatePoolMaintainer)); maintainers.add(new BillingReportMaintainer(controller, intervals.billingReportMaintainer)); + maintainers.add(new CloudAccountVerifier(controller, intervals.cloudAccountVerifier)); } public Upgrader upgrader() { return upgrader; } @@ -147,6 +148,7 @@ public class ControllerMaintenance extends AbstractComponent { private final Duration meteringMonitorMaintainer; private final Duration certificatePoolMaintainer; private final Duration billingReportMaintainer; + private final Duration cloudAccountVerifier; public Intervals(SystemName system) { this.system = Objects.requireNonNull(system); @@ -184,6 +186,7 @@ public class ControllerMaintenance extends AbstractComponent { this.meteringMonitorMaintainer = duration(30, MINUTES); this.certificatePoolMaintainer = duration(15, MINUTES); this.billingReportMaintainer = duration(60, MINUTES); + this.cloudAccountVerifier = duration(10, MINUTES); } private Duration duration(long amount, TemporalUnit unit) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java index 5218da91c46..6c1c4daa1bb 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainer.java @@ -33,7 +33,7 @@ public class EnclaveAccessMaintainer extends ControllerMaintainer { private Set<CloudAccount> externalAccounts() { Set<CloudAccount> accounts = new HashSet<>(); for (Tenant tenant : controller().tenants().asList()) - accounts.addAll(controller().applications().accountsOf(tenant.name())); + tenant.cloudAccounts().forEach(accountInfo -> accounts.add(accountInfo.cloudAccount())); return accounts; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainerTest.java index 5bfac2866ce..1e1079a3314 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/EnclaveAccessMaintainerTest.java @@ -21,17 +21,20 @@ class EnclaveAccessMaintainerTest { void test() { ControllerTester tester = new ControllerTester(); MockEnclaveAccessService amis = tester.serviceRegistry().enclaveAccessService(); - EnclaveAccessMaintainer sharer = new EnclaveAccessMaintainer(tester.controller(), Duration.ofMinutes(1)); + EnclaveAccessMaintainer sharer = new EnclaveAccessMaintainer(tester.controller(), Duration.ofHours(1)); + CloudAccountVerifier accountVerifier = new CloudAccountVerifier(tester.controller(), Duration.ofHours(1)); assertEquals(Set.of(), amis.currentAccounts()); assertEquals(1, sharer.maintain()); assertEquals(Set.of(), amis.currentAccounts()); tester.createTenant("tanten"); + accountVerifier.maintain(); assertEquals(1, sharer.maintain()); assertEquals(Set.of(), amis.currentAccounts()); tester.flagSource().withListFlag(PermanentFlags.CLOUD_ACCOUNTS.id(), List.of("123123123123", "321321321321"), String.class); + accountVerifier.maintain(); assertEquals(1, sharer.maintain()); assertEquals(Set.of(CloudAccount.from("aws:123123123123"), CloudAccount.from("aws:321321321321")), amis.currentAccounts()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index eb376a95c74..8b76613676c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -34,6 +34,9 @@ "name": "ChangeRequestMaintainer" }, { + "name": "CloudAccountVerifier" + }, + { "name": "CloudDatabaseMaintainer" }, { @@ -130,7 +133,5 @@ "name": "VersionStatusUpdater" } ], - "inactive": [ - "DeploymentExpirer" - ] + "inactive": ["DeploymentExpirer"] } |