summaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java/com/yahoo/vespa/hosted/controller
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/main/java/com/yahoo/vespa/hosted/controller')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDb.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java60
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/TenantRoleMaintainer.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/AthenzTenant.java73
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java87
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/DeletedTenant.java39
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/LastLoginInfo.java55
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java88
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java131
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoAddress.java95
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoBillingContact.java74
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/package-info.java8
14 files changed, 62 insertions, 682 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDb.java
index ca173437dd1..a7555307a59 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDb.java
@@ -33,8 +33,6 @@ public class CuratorArchiveBucketDb {
* Policy size limit is 20kb, about 550 bytes for non-tenant related policies. Each tenant
* needs about 500 + len(role_arn) bytes, we limit role_arn to 100 characters, so we can
* fit about (20k - 550) / 600 ~ 32 tenants per bucket.
- *
- * This limit is only enforced for public systems as non-public systems does not use tenant specific policies.
*/
private final static int TENANTS_PER_BUCKET = 30;
@@ -86,7 +84,7 @@ public class CuratorArchiveBucketDb {
.orElseGet(() -> {
// If not, find an existing bucket with space
Optional<ArchiveBucket> unfilledBucket = zoneBuckets.stream()
- .filter(bucket -> !system.isPublic() || bucket.tenants().size() < TENANTS_PER_BUCKET)
+ .filter(bucket -> bucket.tenants().size() < TENANTS_PER_BUCKET)
.findAny();
// And place the tenant in that bucket.
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
index b096a853541..6c4f5ffff9d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainer.java
@@ -2,16 +2,25 @@
package com.yahoo.vespa.hosted.controller.maintenance;
import com.google.common.collect.Maps;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.config.provision.zone.ZoneApi;
+import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.jdisc.Metric;
+import com.yahoo.vespa.flags.BooleanFlag;
+import com.yahoo.vespa.flags.FetchVector;
+import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveService;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.archive.CuratorArchiveBucketDb;
+import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import java.time.Duration;
+import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -27,6 +36,8 @@ public class ArchiveAccessMaintainer extends ControllerMaintainer {
private final ArchiveService archiveService;
private final ZoneRegistry zoneRegistry;
private final Metric metric;
+ private final BooleanFlag archiveEnabled;
+ private final BooleanFlag developerRoleEnabled;
public ArchiveAccessMaintainer(Controller controller, Metric metric, Duration interval) {
super(controller, interval);
@@ -34,6 +45,8 @@ public class ArchiveAccessMaintainer extends ControllerMaintainer {
this.archiveService = controller.serviceRegistry().archiveService();
this.zoneRegistry = controller().zoneRegistry();
this.metric = metric;
+ this.archiveEnabled = Flags.ENABLE_ONPREM_TENANT_S3_ARCHIVE.bindTo(controller().flagSource());
+ this.developerRoleEnabled = Flags.ENABLE_TENANT_DEVELOPER_ROLE.bindTo(controller().flagSource());
}
@Override
@@ -43,22 +56,45 @@ public class ArchiveAccessMaintainer extends ControllerMaintainer {
metric.set(bucketCountMetricName, archiveBucketDb.buckets(zoneId).size(),
metric.createContext(Map.of("zone", zoneId.value()))));
- var tenantArchiveAccessRoles = controller().tenants().asList().stream()
- .filter(t -> t instanceof CloudTenant)
- .map(t -> (CloudTenant) t)
- .filter(t -> t.archiveAccessRole().isPresent())
- .collect(Collectors.toUnmodifiableMap(
- Tenant::name, cloudTenant -> cloudTenant.archiveAccessRole().orElseThrow()));
- zoneRegistry.zones().controllerUpgraded().ids().forEach(zoneId ->
- archiveBucketDb.buckets(zoneId).forEach(archiveBucket ->
- archiveService.updateBucketAndKeyPolicy(zoneId, archiveBucket,
- Maps.filterEntries(tenantArchiveAccessRoles,
- entry -> archiveBucket.tenants().contains(entry.getKey())))
- )
+ zoneRegistry.zones().controllerUpgraded().zones().forEach(z -> {
+ ZoneId zoneId = z.getId();
+ var tenantArchiveAccessRoles = tenantArchiveAccessRoles(z);
+ archiveBucketDb.buckets(zoneId).forEach(archiveBucket ->
+ archiveService.updateBucketAndKeyPolicy(zoneId, archiveBucket,
+ Maps.filterEntries(tenantArchiveAccessRoles,
+ entry -> archiveBucket.tenants().contains(entry.getKey())))
+ );
+ }
);
return 1.0;
}
+ private Map<TenantName, String> tenantArchiveAccessRoles(ZoneApi zone) {
+ List<Tenant> tenants = controller().tenants().asList();
+ if (zoneRegistry.system().isPublic()) {
+ return tenants.stream()
+ .filter(t -> t instanceof CloudTenant)
+ .map(t -> (CloudTenant) t)
+ .filter(t -> t.archiveAccessRole().isPresent())
+ .collect(Collectors.toUnmodifiableMap(
+ Tenant::name, cloudTenant -> cloudTenant.archiveAccessRole().orElseThrow()));
+ } else {
+ return tenants.stream()
+ .filter(t -> t instanceof AthenzTenant
+ && enabled(archiveEnabled, t, zone) && enabled(developerRoleEnabled, t, zone))
+ .map(Tenant::name)
+ .collect(Collectors.toUnmodifiableMap(
+ Function.identity(), t -> zoneRegistry.tenantDeveloperRoleArn(t).orElseThrow()));
+
+ }
+ }
+
+ private boolean enabled(BooleanFlag flag, Tenant tenant, ZoneApi zone) {
+ return flag.with(FetchVector.Dimension.TENANT_ID, tenant.name().value())
+ .with(FetchVector.Dimension.ZONE_ID, zone.getId().value())
+ .value();
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/TenantRoleMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/TenantRoleMaintainer.java
index ce6f9c802d6..d2b43dc63d9 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/TenantRoleMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/TenantRoleMaintainer.java
@@ -27,9 +27,7 @@ public class TenantRoleMaintainer extends ControllerMaintainer {
var tenants = controller().tenants().asList();
// Create separate athenz service for all tenants
- tenants.stream()
- .map(Tenant::name)
- .forEach(roleService::createTenantRole);
+ tenants.forEach(roleService::createTenantRole);
// Until we have moved to separate athenz service per tenant, make sure we update the shared policy
// to allow ssh logins for hosts in prod/perf with a separate tenant iam role.
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 1a2acb82348..98ac789de04 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -1967,6 +1967,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.flatMap(options -> optional("vespaVersion", options))
.map(Version::fromString);
+ ensureApplicationExists(TenantAndApplicationId.from(id), request);
+
controller.jobController().deploy(id, type, version, applicationPackage);
RunId runId = controller.jobController().last(id, type).get().id();
Slime slime = new Slime();
@@ -2617,6 +2619,8 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
applicationPackage,
Optional.of(requireUserPrincipal(request)));
+ ensureApplicationExists(TenantAndApplicationId.from(tenant, application), request);
+
return JobControllerApiHandlerHelper.submitResponse(controller.jobController(),
tenant,
application,
@@ -2718,5 +2722,13 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.anyMatch(definition -> definition == RoleDefinition.hostedOperator);
}
+ private void ensureApplicationExists(TenantAndApplicationId id, HttpRequest request) {
+ if (controller.applications().getApplication(id).isEmpty()) {
+ log.fine("Application does not exist in public, creating: " + id);
+ var credentials = accessControlRequests.credentials(id.tenant(), null /* not used on public */ , request.getJDiscRequest());
+ controller.applications().createApplication(id, credentials);
+ }
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
index 157f57b3bea..7e88f127026 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java
@@ -20,10 +20,7 @@ import com.yahoo.slime.SlimeStream;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.text.Text;
import com.yahoo.vespa.configserver.flags.FlagsDb;
-import com.yahoo.vespa.flags.BooleanFlag;
-import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
-import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.IntFlag;
import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.hosted.controller.Controller;
@@ -71,9 +68,7 @@ public class UserApiHandler extends LoggingRequestHandler {
private final UserManagement users;
private final Controller controller;
private final FlagsDb flagsDb;
- private final BooleanFlag enable_public_signup_flow;
private final IntFlag maxTrialTenants;
- private final BooleanFlag enabledHorizonDashboard;
@Inject
public UserApiHandler(Context parentCtx, UserManagement users, Controller controller, FlagSource flagSource, FlagsDb flagsDb) {
@@ -81,9 +76,7 @@ public class UserApiHandler extends LoggingRequestHandler {
this.users = users;
this.controller = controller;
this.flagsDb = flagsDb;
- this.enable_public_signup_flow = PermanentFlags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
this.maxTrialTenants = PermanentFlags.MAX_TRIAL_TENANTS.bindTo(flagSource);
- this.enabledHorizonDashboard = Flags.ENABLED_HORIZON_DASHBOARD.bindTo(flagSource);
}
@Override
@@ -173,9 +166,6 @@ public class UserApiHandler extends LoggingRequestHandler {
root.setBool("isPublic", controller.system().isPublic());
root.setBool("isCd", controller.system().isCd());
- // TODO (freva): Remove after users have migrated to use 'flags'
- root.setBool(enable_public_signup_flow.id().toString(),
- enable_public_signup_flow.with(FetchVector.Dimension.CONSOLE_USER_EMAIL, user.email()).value());
root.setBool("hasTrialCapacity", hasTrialCapacity());
toSlime(root.setObject("user"), user);
@@ -190,10 +180,6 @@ public class UserApiHandler extends LoggingRequestHandler {
Cursor tenantRolesObject = tenantObject.setArray("roles");
tenantRolesByTenantName.getOrDefault(tenant, List.of())
.forEach(role -> tenantRolesObject.addString(role.definition().name()));
- if (controller.system().isPublic()) {
- tenantObject.setBool(enabledHorizonDashboard.id().toString(),
- enabledHorizonDashboard.with(FetchVector.Dimension.TENANT_ID, tenant.value()).value());
- }
});
if (!operatorRoles.isEmpty()) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/AthenzTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/AthenzTenant.java
deleted file mode 100644
index 7fa46031c98..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/AthenzTenant.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2018 Yahoo Holdings. 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 com.yahoo.vespa.athenz.api.AthenzDomain;
-import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
-import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
-
-import java.time.Instant;
-import java.util.Objects;
-import java.util.Optional;
-
-/**
- * Represents an Athenz tenant in hosted Vespa.
- *
- * @author mpolden
- */
-public class AthenzTenant extends Tenant {
-
- private final AthenzDomain domain;
- private final Property property;
- private final Optional<PropertyId> propertyId;
-
- /**
- * This should only be used by serialization.
- * Use {@link #create(TenantName, AthenzDomain, Property, Optional, Instant)}.
- * */
- public AthenzTenant(TenantName name, AthenzDomain domain, Property property, Optional<PropertyId> propertyId,
- Optional<Contact> contact, Instant createdAt, LastLoginInfo lastLoginInfo) {
- super(name, createdAt, lastLoginInfo, contact);
- this.domain = Objects.requireNonNull(domain, "domain must be non-null");
- this.property = Objects.requireNonNull(property, "property must be non-null");
- this.propertyId = Objects.requireNonNull(propertyId, "propertyId must be non-null");
- }
-
- /** Property name of this tenant */
- public Property property() {
- return property;
- }
-
- /** Property ID of the tenant, if any */
- public Optional<PropertyId> propertyId() {
- return propertyId;
- }
-
- /** Athenz domain of this tenant */
- public AthenzDomain domain() {
- return domain;
- }
-
- /** Returns true if tenant is in given domain */
- public boolean in(AthenzDomain domain) {
- return this.domain.equals(domain);
- }
-
- @Override
- public String toString() {
- return "athenz tenant '" + name() + "'";
- }
-
- /** Create a new Athenz tenant */
- public static AthenzTenant create(TenantName name, AthenzDomain domain, Property property,
- Optional<PropertyId> propertyId, Instant createdAt) {
- return new AthenzTenant(requireName(name), domain, property, propertyId, Optional.empty(), createdAt, LastLoginInfo.EMPTY);
- }
-
- @Override
- public Type type() {
- return Type.athenz;
- }
-
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
deleted file mode 100644
index 1060b118beb..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/CloudTenant.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2020 Oath Inc. 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.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableBiMap;
-import com.yahoo.config.provision.TenantName;
-import com.yahoo.text.Text;
-import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
-
-import java.security.Principal;
-import java.security.PublicKey;
-import java.time.Instant;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.regex.Pattern;
-
-/**
- * A paying tenant in a Vespa cloud service.
- *
- * @author jonmv
- */
-public class CloudTenant extends Tenant {
-
- private static final Pattern VALID_ARCHIVE_ACCESS_ROLE_PATTERN = Pattern.compile("arn:aws:iam::\\d{12}:.+");
-
- private final Optional<Principal> creator;
- private final BiMap<PublicKey, Principal> developerKeys;
- private final TenantInfo info;
- private final List<TenantSecretStore> tenantSecretStores;
- private final Optional<String> archiveAccessRole;
-
- /** Public for the serialization layer — do not use! */
- public CloudTenant(TenantName name, Instant createdAt, LastLoginInfo lastLoginInfo, Optional<Principal> creator,
- BiMap<PublicKey, Principal> developerKeys, TenantInfo info,
- List<TenantSecretStore> tenantSecretStores, Optional<String> archiveAccessRole) {
- super(name, createdAt, lastLoginInfo, Optional.empty());
- this.creator = creator;
- this.developerKeys = developerKeys;
- this.info = Objects.requireNonNull(info);
- this.tenantSecretStores = tenantSecretStores;
- this.archiveAccessRole = archiveAccessRole;
- if (!archiveAccessRole.map(role -> VALID_ARCHIVE_ACCESS_ROLE_PATTERN.matcher(role).matches()).orElse(true))
- throw new IllegalArgumentException(Text.format("Invalid archive access role '%s': Must match expected pattern: '%s'",
- archiveAccessRole.get(), VALID_ARCHIVE_ACCESS_ROLE_PATTERN.pattern()));
- if (archiveAccessRole.map(role -> role.length() > 100).orElse(false))
- throw new IllegalArgumentException("Invalid archive access role too long, must be 100 or less characters");
- }
-
- /** Creates a tenant with the given name, provided it passes validation. */
- public static CloudTenant create(TenantName tenantName, Instant createdAt, Principal creator) {
- return new CloudTenant(requireName(tenantName),
- createdAt,
- LastLoginInfo.EMPTY,
- Optional.ofNullable(creator),
- ImmutableBiMap.of(), TenantInfo.EMPTY, List.of(), Optional.empty());
- }
-
- /** The user that created the tenant */
- public Optional<Principal> creator() {
- return creator;
- }
-
- /** Legal name, addresses etc */
- public TenantInfo info() {
- return info;
- }
-
- /** An iam role which is allowed to access the S3 (log, dump) archive) */
- public Optional<String> archiveAccessRole() {
- return archiveAccessRole;
- }
-
- /** Returns the set of developer keys and their corresponding developers for this tenant. */
- public BiMap<PublicKey, Principal> developerKeys() { return developerKeys; }
-
- /** List of configured secret stores */
- public List<TenantSecretStore> tenantSecretStores() {
- return tenantSecretStores;
- }
-
- @Override
- public Type type() {
- return Type.cloud;
- }
-
-}
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
deleted file mode 100644
index cf6d73cb8f8..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/DeletedTenant.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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/LastLoginInfo.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/LastLoginInfo.java
deleted file mode 100644
index 15f2f97e7d1..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/LastLoginInfo.java
+++ /dev/null
@@ -1,55 +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.tenant;
-
-import java.time.Instant;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * @author freva
- */
-public class LastLoginInfo {
-
- public static final LastLoginInfo EMPTY = new LastLoginInfo(Map.of());
-
- private final Map<UserLevel, Instant> lastLoginByUserLevel;
-
- public LastLoginInfo(Map<UserLevel, Instant> lastLoginByUserLevel) {
- this.lastLoginByUserLevel = Map.copyOf(lastLoginByUserLevel);
- }
-
- public Optional<Instant> get(UserLevel userLevel) {
- return Optional.ofNullable(lastLoginByUserLevel.get(userLevel));
- }
-
- /**
- * Returns new instance with updated last login time if the given {@code loginAt} timestamp is after the current
- * for the given {@code userLevel}, otherwise returns this
- */
- public LastLoginInfo withLastLoginIfLater(UserLevel userLevel, Instant loginAt) {
- Instant lastLogin = lastLoginByUserLevel.getOrDefault(userLevel, Instant.EPOCH);
- if (loginAt.isAfter(lastLogin)) {
- Map<UserLevel, Instant> lastLoginByUserLevel = new HashMap<>(this.lastLoginByUserLevel);
- lastLoginByUserLevel.put(userLevel, loginAt);
- return new LastLoginInfo(lastLoginByUserLevel);
- }
- return this;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- LastLoginInfo lastLoginInfo = (LastLoginInfo) o;
- return lastLoginByUserLevel.equals(lastLoginInfo.lastLoginByUserLevel);
- }
-
- @Override
- public int hashCode() {
- return lastLoginByUserLevel.hashCode();
- }
-
- public enum UserLevel { user, developer, administrator };
-}
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
deleted file mode 100644
index 80982d70107..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2018 Yahoo Holdings. 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 com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
-
-import java.time.Instant;
-import java.util.Objects;
-import java.util.Optional;
-
-/**
- * A tenant in hosted Vespa.
- *
- * @author mpolden
- */
-public abstract class Tenant {
-
- private final TenantName name;
- private final Instant createdAt;
- private final LastLoginInfo lastLoginInfo;
- private final Optional<Contact> contact;
-
- Tenant(TenantName name, Instant createdAt, LastLoginInfo lastLoginInfo, Optional<Contact> contact) {
- this.name = name;
- this.createdAt = createdAt;
- this.lastLoginInfo = lastLoginInfo;
- this.contact = contact;
- }
-
- /** Name of this tenant */
- public TenantName name() {
- return name;
- }
-
- /** Instant when the tenant was created */
- public Instant createdAt() {
- return createdAt;
- }
-
- /** Returns login information for this tenant */
- public LastLoginInfo lastLoginInfo() {
- return lastLoginInfo;
- }
-
- /** Contact information for this tenant */
- public Optional<Contact> contact() {
- return contact;
- }
-
- public abstract Type type();
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Tenant tenant = (Tenant) o;
- return Objects.equals(name, tenant.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name);
- }
-
- public static TenantName requireName(TenantName name) {
- if ( ! name.value().matches("^(?=.{1,20}$)[a-z](-?[a-z0-9]+)*$")) {
- throw new IllegalArgumentException("New tenant or application names must start with a letter, may " +
- "contain no more than 20 characters, and may only contain lowercase " +
- "letters, digits or dashes, but no double-dashes.");
- }
- return name;
- }
-
-
- public enum Type {
-
- /** Tenant authenticated through Athenz. */
- athenz,
-
- /** Tenant authenticated through some cloud identity provider. */
- cloud,
-
- /** Tenant has been deleted. */
- deleted,
-
- }
-
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java
deleted file mode 100644
index a20477d7aab..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2020 Oath Inc. 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.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Tenant information beyond technical tenant id and user authorizations.
- *
- * This info is used to capture generic support information and invoiced billing information.
- *
- * All fields are non null but strings can be empty
- *
- * @author smorgrav
- */
-public class TenantInfo {
- private final String name;
- private final String email;
- private final String website;
- private final String contactName;
- private final String contactEmail;
- private final String invoiceEmail;
- private final TenantInfoAddress address;
- private final TenantInfoBillingContact billingContact;
-
- TenantInfo(String name, String email, String website, String contactName, String contactEmail,
- String invoiceEmail, TenantInfoAddress address, TenantInfoBillingContact billingContact) {
- this.name = Objects.requireNonNull(name);
- this.email = Objects.requireNonNull(email);
- this.website = Objects.requireNonNull(website);
- this.contactName = Objects.requireNonNull(contactName);
- this.contactEmail = Objects.requireNonNull(contactEmail);
- this.invoiceEmail = Objects.requireNonNull(invoiceEmail);
- this.address = Objects.requireNonNull(address);
- this.billingContact = Objects.requireNonNull(billingContact);
- }
-
- public static final TenantInfo EMPTY = new TenantInfo("","","", "", "", "",
- TenantInfoAddress.EMPTY, TenantInfoBillingContact.EMPTY);
-
- public String name() {
- return name;
- }
-
- public String email() {
- return email;
- }
-
- public String website() {
- return website;
- }
-
- public String contactName() {
- return contactName;
- }
-
- public String contactEmail() {
- return contactEmail;
- }
-
- public String invoiceEmail() {
- return invoiceEmail;
- }
-
- public TenantInfoAddress address() {
- return address;
- }
-
- public TenantInfoBillingContact billingContact() {
- return billingContact;
- }
-
- public TenantInfo withName(String newName) {
- return new TenantInfo(newName, email, website, contactName, contactEmail, invoiceEmail, address, billingContact);
- }
-
- public TenantInfo withEmail(String newEmail) {
- return new TenantInfo(name, newEmail, website, contactName, contactEmail, invoiceEmail, address, billingContact);
- }
-
- public TenantInfo withWebsite(String newWebsite) {
- return new TenantInfo(name, email, newWebsite, contactName, contactEmail, invoiceEmail, address, billingContact);
- }
-
- public TenantInfo withContactName(String newContactName) {
- return new TenantInfo(name, email, website, newContactName, contactEmail, invoiceEmail, address, billingContact);
- }
-
- public TenantInfo withContactEmail(String newContactEmail) {
- return new TenantInfo(name, email, website, contactName, newContactEmail, invoiceEmail, address, billingContact);
- }
-
- public TenantInfo withInvoiceEmail(String newInvoiceEmail) {
- return new TenantInfo(name, email, website, contactName, contactEmail, newInvoiceEmail, address, billingContact);
- }
-
- public TenantInfo withAddress(TenantInfoAddress newAddress) {
- return new TenantInfo(name, email, website, contactName, contactEmail, invoiceEmail, newAddress, billingContact);
- }
-
- public TenantInfo withBillingContact(TenantInfoBillingContact newBillingContact) {
- return new TenantInfo(name, email, website, contactName, contactEmail, invoiceEmail, address, newBillingContact);
- }
-
- public boolean isEmpty() {
- return this.equals(EMPTY);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- TenantInfo that = (TenantInfo) o;
- return name.equals(that.name) &&
- email.equals(that.email) &&
- website.equals(that.website) &&
- contactName.equals(that.contactName) &&
- contactEmail.equals(that.contactEmail) &&
- invoiceEmail.equals(that.invoiceEmail) &&
- address.equals(that.address) &&
- billingContact.equals(that.billingContact);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, email, website, contactName, contactEmail, invoiceEmail, address, billingContact);
- }
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoAddress.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoAddress.java
deleted file mode 100644
index a12f351abd6..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoAddress.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.tenant;
-
-import java.util.Objects;
-
-/**
- * Address formats are quite diverse across the world both in therms of what fields are used, named and
- * the order of them.
- *
- * To be generic a little future proof the address fields here are a mix of free text (address lines) and fixed fields.
- * The address lines can be street address, P.O box, c/o name, apartment, suite, unit, building floor etc etc.
- *
- * All fields are mandatory but can be an empty string (ie. not null)
- *
- * @author smorgrav
- */
-public class TenantInfoAddress {
-
- private final String addressLines;
- private final String postalCodeOrZip;
- private final String city;
- private final String stateRegionProvince;
- private final String country;
-
- TenantInfoAddress(String addressLines, String postalCodeOrZip, String city, String country, String stateRegionProvince) {
- this.addressLines = Objects.requireNonNull(addressLines);;
- this.city = Objects.requireNonNull(city);
- this.postalCodeOrZip = Objects.requireNonNull(postalCodeOrZip);
- this.country = Objects.requireNonNull(country);
- this.stateRegionProvince = Objects.requireNonNull(stateRegionProvince);
- }
-
- public static final TenantInfoAddress EMPTY = new TenantInfoAddress("","","", "", "");
-
- public String addressLines() {
- return addressLines;
- }
-
- public String postalCodeOrZip() {
- return postalCodeOrZip;
- }
-
- public String city() {
- return city;
- }
-
- public String country() {
- return country;
- }
-
- public String stateRegionProvince() {
- return stateRegionProvince;
- }
-
- public TenantInfoAddress withAddressLines(String newAddressLines) {
- return new TenantInfoAddress(newAddressLines, postalCodeOrZip, city, country, stateRegionProvince);
- }
-
- public TenantInfoAddress withPostalCodeOrZip(String newPostalCodeOrZip) {
- return new TenantInfoAddress(addressLines, newPostalCodeOrZip, city, country, stateRegionProvince);
- }
-
- public TenantInfoAddress withCity(String newCity) {
- return new TenantInfoAddress(addressLines, postalCodeOrZip, newCity, country, stateRegionProvince);
- }
-
- public TenantInfoAddress withCountry(String newCountry) {
- return new TenantInfoAddress(addressLines, postalCodeOrZip, city, newCountry, stateRegionProvince);
- }
-
- public TenantInfoAddress withStateRegionProvince(String newStateRegionProvince) {
- return new TenantInfoAddress(addressLines, postalCodeOrZip, city, country, newStateRegionProvince);
- }
-
- public boolean isEmpty() {
- return this.equals(EMPTY);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- TenantInfoAddress that = (TenantInfoAddress) o;
- return addressLines.equals(that.addressLines) &&
- postalCodeOrZip.equals(that.postalCodeOrZip) &&
- city.equals(that.city) &&
- stateRegionProvince.equals(that.stateRegionProvince) &&
- country.equals(that.country);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(addressLines, postalCodeOrZip, city, stateRegionProvince, country);
- }
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoBillingContact.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoBillingContact.java
deleted file mode 100644
index a00dd626f0a..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfoBillingContact.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.tenant;
-
-import java.util.Objects;
-
-/**
- * @author smorgrav
- */
-public class TenantInfoBillingContact {
- private final String name;
- private final String email;
- private final String phone;
- private final TenantInfoAddress address;
-
- TenantInfoBillingContact(String name, String email, String phone, TenantInfoAddress address) {
- this.name = Objects.requireNonNull(name);
- this.email = Objects.requireNonNull(email);
- this.phone = Objects.requireNonNull(phone);
- this.address = Objects.requireNonNull(address);
- }
-
- public static final TenantInfoBillingContact EMPTY =
- new TenantInfoBillingContact("","", "", TenantInfoAddress.EMPTY);
-
- public String name() {
- return name;
- }
-
- public String email() { return email; }
-
- public String phone() {
- return phone;
- }
-
- public TenantInfoAddress address() {
- return address;
- }
-
- public TenantInfoBillingContact withName(String newName) {
- return new TenantInfoBillingContact(newName, email, phone, address);
- }
-
- public TenantInfoBillingContact withEmail(String newEmail) {
- return new TenantInfoBillingContact(name, newEmail, phone, address);
- }
-
- public TenantInfoBillingContact withPhone(String newPhone) {
- return new TenantInfoBillingContact(name, email, newPhone, address);
- }
-
- public TenantInfoBillingContact withAddress(TenantInfoAddress newAddress) {
- return new TenantInfoBillingContact(name, email, phone, newAddress);
- }
-
- public boolean isEmpty() {
- return this.equals(EMPTY);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- TenantInfoBillingContact that = (TenantInfoBillingContact) o;
- return name.equals(that.name) &&
- email.equals(that.email) &&
- phone.equals(that.phone) &&
- address.equals(that.address);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, email, phone, address);
- }
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/package-info.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/package-info.java
deleted file mode 100644
index 9218bfcd850..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @author mpolden
- */
-@ExportPackage
-package com.yahoo.vespa.hosted.controller.tenant;
-
-import com.yahoo.osgi.annotation.ExportPackage;