diff options
Diffstat (limited to 'controller-server')
4 files changed, 81 insertions, 16 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java index 6b167f26314..4d5aeaeb3c6 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java @@ -19,6 +19,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact; import com.yahoo.vespa.hosted.controller.api.integration.organization.BillingInfo; import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant; import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; +import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; import com.yahoo.vespa.hosted.controller.tenant.Tenant; import com.yahoo.vespa.hosted.controller.tenant.TenantInfo; @@ -56,6 +57,7 @@ public class TenantSerializer { private static final String propertyIdField = "propertyId"; private static final String creatorField = "creator"; private static final String createdAtField = "createdAt"; + private static final String deletedAtField = "deletedAt"; private static final String contactField = "contact"; private static final String contactUrlField = "contactUrl"; private static final String propertyUrlField = "propertyUrl"; @@ -84,9 +86,10 @@ public class TenantSerializer { toSlime(tenant.lastLoginInfo(), tenantObject.setObject(lastLoginInfoField)); switch (tenant.type()) { - case athenz: toSlime((AthenzTenant) tenant, tenantObject); break; - case cloud: toSlime((CloudTenant) tenant, tenantObject); break; - default: throw new IllegalArgumentException("Unexpected tenant type '" + tenant.type() + "'."); + case athenz: toSlime((AthenzTenant) tenant, tenantObject); break; + case cloud: toSlime((CloudTenant) tenant, tenantObject); break; + case deleted: toSlime((DeletedTenant) tenant, tenantObject); break; + default: throw new IllegalArgumentException("Unexpected tenant type '" + tenant.type() + "'."); } return slime; } @@ -114,6 +117,10 @@ public class TenantSerializer { tenant.archiveAccessRole().ifPresent(role -> root.setString(archiveAccessRoleField, role)); } + private void toSlime(DeletedTenant tenant, Cursor root) { + root.setLong(deletedAtField, tenant.deletedAt().toEpochMilli()); + } + private void developerKeysToSlime(BiMap<PublicKey, Principal> keys, Cursor array) { keys.forEach((key, user) -> { Cursor object = array.addObject(); @@ -139,9 +146,10 @@ public class TenantSerializer { Tenant.Type type = typeOf(tenantObject.field(typeField).asString()); switch (type) { - case athenz: return athenzTenantFrom(tenantObject); - case cloud: return cloudTenantFrom(tenantObject); - default: throw new IllegalArgumentException("Unexpected tenant type '" + type + "'."); + case athenz: return athenzTenantFrom(tenantObject); + case cloud: return cloudTenantFrom(tenantObject); + case deleted: return deletedTenantFrom(tenantObject); + default: throw new IllegalArgumentException("Unexpected tenant type '" + type + "'."); } } @@ -168,6 +176,13 @@ public class TenantSerializer { return new CloudTenant(name, createdAt, lastLoginInfo, creator, developerKeys, info, tenantSecretStores, archiveAccessRole); } + private DeletedTenant deletedTenantFrom(Inspector tenantObject) { + TenantName name = TenantName.from(tenantObject.field(nameField).asString()); + Instant createdAt = SlimeUtils.instant(tenantObject.field(createdAtField)); + Instant deletedAt = SlimeUtils.instant(tenantObject.field(deletedAtField)); + return new DeletedTenant(name, createdAt, deletedAt); + } + private BiMap<PublicKey, Principal> developerKeysFromSlime(Inspector array) { ImmutableBiMap.Builder<PublicKey, Principal> keys = ImmutableBiMap.builder(); array.traverse((ArrayTraverser) (__, keyObject) -> @@ -321,23 +336,20 @@ public class TenantSerializer { return personLists; } - private BillingInfo billingInfoFrom(Inspector billingInfoObject) { - return new BillingInfo(billingInfoObject.field(customerIdField).asString(), - billingInfoObject.field(productCodeField).asString()); - } - private static Tenant.Type typeOf(String value) { switch (value) { - case "athenz": return Tenant.Type.athenz; - case "cloud": return Tenant.Type.cloud; + case "athenz": return Tenant.Type.athenz; + case "cloud": return Tenant.Type.cloud; + case "deleted": return Tenant.Type.deleted; default: throw new IllegalArgumentException("Unknown tenant type '" + value + "'."); } } private static String valueOf(Tenant.Type type) { switch (type) { - case athenz: return "athenz"; - case cloud: return "cloud"; + case athenz: return "athenz"; + case cloud: return "cloud"; + case deleted: return "deleted"; default: throw new IllegalArgumentException("Unexpected tenant type '" + type + "'."); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/DeletedTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/DeletedTenant.java new file mode 100644 index 00000000000..cf6d73cb8f8 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/DeletedTenant.java @@ -0,0 +1,39 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.tenant; + +import com.yahoo.config.provision.TenantName; + +import java.time.Instant; +import java.util.Objects; +import java.util.Optional; + +/** + * Represents a tenant that has been deleted. Exists to prevent creation of a new tenant with the same name. + * + * @author freva + */ +public class DeletedTenant extends Tenant { + + private final Instant deletedAt; + + public DeletedTenant(TenantName name, Instant createdAt, Instant deletedAt) { + super(name, createdAt, LastLoginInfo.EMPTY, Optional.empty()); + this.deletedAt = Objects.requireNonNull(deletedAt, "deletedAt must be non-null"); + } + + /** Instant when the tenant was deleted */ + public Instant deletedAt() { + return deletedAt; + } + + @Override + public String toString() { + return "deleted tenant '" + name() + "'"; + } + + @Override + public Type type() { + return Type.deleted; + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java index f8b54e7eff3..80982d70107 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java @@ -78,7 +78,10 @@ public abstract class Tenant { athenz, /** Tenant authenticated through some cloud identity provider. */ - cloud + cloud, + + /** Tenant has been deleted. */ + deleted, } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java index e123c4cca62..465a9160aca 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java @@ -14,6 +14,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretSto import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal; import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant; import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; +import com.yahoo.vespa.hosted.controller.tenant.DeletedTenant; import com.yahoo.vespa.hosted.controller.tenant.LastLoginInfo; import com.yahoo.vespa.hosted.controller.tenant.TenantInfo; import com.yahoo.vespa.hosted.controller.tenant.TenantInfoAddress; @@ -172,6 +173,16 @@ public class TenantSerializerTest { assertEquals(fullInfo, roundTripInfo); } + @Test + public void deleted_tenant() { + DeletedTenant tenant = new DeletedTenant( + TenantName.from("tenant1"), Instant.ofEpochMilli(1234L), Instant.ofEpochMilli(2345L)); + DeletedTenant serialized = (DeletedTenant) serializer.tenantFrom(serializer.toSlime(tenant)); + assertEquals(tenant.name(), serialized.name()); + assertEquals(tenant.createdAt(), serialized.createdAt()); + assertEquals(tenant.deletedAt(), serialized.deletedAt()); + } + private static Contact contact() { return new Contact( URI.create("http://contact1.test"), |