summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@verizonmedia.com>2021-09-27 14:57:08 +0200
committerValerij Fredriksen <valerijf@verizonmedia.com>2021-09-27 14:57:08 +0200
commit8f527a35bc80ac3cd936db92d7b3ba4efde2d9ec (patch)
treeaaba30a621487c1f536ec750d496d2baf89ddf25 /controller-server
parent1e630a4f57ba52f3194895837d2f17b8cbc56ada (diff)
parentc4feaca0cfbf19b18c7b2ced33a1e18f80534b38 (diff)
Merge branch 'master' into ogronnesby/create-application-on-deploy
Diffstat (limited to 'controller-server')
-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/deployment/JobController.java2
-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/DeploymentUpgrader.java1
-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/horizon/HorizonApiHandler.java11
-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
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java67
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json1
24 files changed, 89 insertions, 755 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/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 652f8630cb6..88d440b52b9 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -518,6 +518,8 @@ public class JobController {
type,
new Versions(platform.orElse(applicationPackage.deploymentSpec().majorVersion()
.flatMap(controller.applications()::lastCompatibleVersion)
+ .or(() -> lastRun.map(run -> run.versions().targetPlatform())
+ .filter(controller.readVersionStatus()::isActive))
.orElseGet(controller::readSystemVersion)),
version,
lastRun.map(run -> run.versions().targetPlatform()),
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/DeploymentUpgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
index 97e9a233f9f..0bf47f85420 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java
@@ -46,7 +46,6 @@ public class DeploymentUpgrader extends ControllerMaintainer {
Run last = controller().jobController().last(job).get();
Versions target = new Versions(systemVersion, last.versions().targetApplication(), Optional.of(last.versions().targetPlatform()), Optional.of(last.versions().targetApplication()));
if ( ! deployment.version().isBefore(target.targetPlatform())) continue;
- if ( controller().clock().instant().isBefore(last.start().plus(Duration.ofDays(1)))) continue;
if ( ! isLikelyNightFor(job)) continue;
log.log(Level.FINE, "Upgrading deployment of " + instance.id() + " in " + deployment.zone());
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/horizon/HorizonApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java
index 6619b2ff5c6..61bf8feae35 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java
@@ -14,8 +14,6 @@ import com.yahoo.vespa.flags.FetchVector;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.hosted.controller.Controller;
-import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
-import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.integration.horizon.HorizonClient;
import com.yahoo.vespa.hosted.controller.api.integration.horizon.HorizonResponse;
import com.yahoo.vespa.hosted.controller.api.role.Role;
@@ -28,7 +26,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.EnumSet;
-import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
@@ -41,7 +38,6 @@ import java.util.stream.Collectors;
*/
public class HorizonApiHandler extends LoggingRequestHandler {
- private final BillingController billingController;
private final SystemName systemName;
private final HorizonClient client;
private final BooleanFlag enabledHorizonDashboard;
@@ -52,7 +48,6 @@ public class HorizonApiHandler extends LoggingRequestHandler {
@Inject
public HorizonApiHandler(LoggingRequestHandler.Context parentCtx, Controller controller, FlagSource flagSource) {
super(parentCtx);
- this.billingController = controller.serviceRegistry().billingController();
this.systemName = controller.system();
this.client = controller.serviceRegistry().horizonClient();
this.enabledHorizonDashboard = Flags.ENABLED_HORIZON_DASHBOARD.bindTo(flagSource);
@@ -123,13 +118,11 @@ public class HorizonApiHandler extends LoggingRequestHandler {
}
private Set<TenantName> getAuthorizedTenants(Set<Role> roles) {
- var horizonEnabled = roles.stream()
+ return roles.stream()
.filter(TenantRole.class::isInstance)
.map(role -> ((TenantRole) role).tenant())
.filter(tenant -> enabledHorizonDashboard.with(FetchVector.Dimension.TENANT_ID, tenant.value()).value())
- .collect(Collectors.toList());
-
- return new HashSet<>(billingController.tenantsWithPlan(horizonEnabled, PlanId.from("pay-as-you-go")));
+ .collect(Collectors.toSet());
}
private static class JsonInputStreamResponse extends HttpResponse {
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;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
index fe03b69a3fe..7ce17aff782 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
@@ -9,6 +9,7 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.RoutingMethod;
import com.yahoo.config.provision.zone.UpgradePolicy;
import com.yahoo.config.provision.zone.ZoneApi;
@@ -216,6 +217,8 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
return URI.create("https://api.tld:4443/");
}
+ @Override public Optional<String> tenantDeveloperRoleArn(TenantName tenant) { return Optional.empty(); }
+
@Override
public boolean hasZone(ZoneId zoneId) {
return zones.stream().anyMatch(zone -> zone.getId().equals(zoneId));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java
index ec33c8a7048..1c07a321953 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java
@@ -55,19 +55,13 @@ public class DeploymentUpgraderTest {
assertEquals(start, tester.jobs().last(devApp.instanceId(), devUsEast1).get().start());
assertEquals(start, tester.jobs().last(prodApp.instanceId(), productionUsWest1).get().start());
- // 14 hours pass, but not upgraded before a day has passed since last deployment
- tester.clock().advance(Duration.ofHours(14));
+ // 11 hours pass, but not upgraded since it's not likely in the middle of the night
+ tester.clock().advance(Duration.ofHours(11));
upgrader.maintain();
assertEquals(start, tester.jobs().last(devApp.instanceId(), devUsEast1).get().start());
assertEquals(start, tester.jobs().last(prodApp.instanceId(), productionUsWest1).get().start());
- // 35 hours pass, but not upgraded since it's not likely in the middle of the night
- tester.clock().advance(Duration.ofHours(21));
- upgrader.maintain();
- assertEquals(start, tester.jobs().last(devApp.instanceId(), devUsEast1).get().start());
- assertEquals(start, tester.jobs().last(prodApp.instanceId(), productionUsWest1).get().start());
-
- // 38 hours pass, and the dev deployment, only, is upgraded
+ // 14 hours pass, and the dev deployment, only, is upgraded
tester.clock().advance(Duration.ofHours(3));
upgrader.maintain();
assertEquals(tester.clock().instant().truncatedTo(MILLIS), tester.jobs().last(devApp.instanceId(), devUsEast1).get().start());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index cd73721ce4f..03a88c7a8c4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -1,4 +1,4 @@
-// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.restapi.application;
import ai.vespa.hosted.api.MultiPartStreamer;
@@ -250,7 +250,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
var app1 = deploymentTester.newDeploymentContext(id);
// POST (deploy) an application to start a manual deployment in prod is not allowed
- MultiPartStreamer entity = createApplicationDeployData(applicationPackageInstance1, true);
+ MultiPartStreamer entity = createApplicationDeployData(applicationPackageInstance1);
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploy/production-us-east-3/", POST)
.data(entity)
.userIdentity(USER_ID),
@@ -289,7 +289,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST an application package is not generally allowed under user instance
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/otheruser/deploy/dev-us-east-1", POST)
.userIdentity(OTHER_USER_ID)
- .data(createApplicationDeployData(applicationPackageInstance1, false)),
+ .data(createApplicationDeployData(applicationPackageInstance1)),
accessDenied,
403);
@@ -303,7 +303,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST an application package is not allowed under user instance for tenant admins
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/myuser/deploy/dev-us-east-1", POST)
.userIdentity(USER_ID)
- .data(createApplicationDeployData(applicationPackageInstance1, false)),
+ .data(createApplicationDeployData(applicationPackageInstance1)),
new File("deployment-job-accepted-2.json"));
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/myuser/job/dev-us-east-1/diff/1", GET).userIdentity(HOSTED_VESPA_OPERATOR),
@@ -1026,38 +1026,24 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
@Test
- public void testDeployDirectly() {
+ public void testDeployWithApplicationPackage() {
// Setup
- createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID);
addUserToHostedOperatorRole(HostedAthenzIdentities.from(HOSTED_VESPA_OPERATOR));
- // Create tenant
- tester.assertResponse(request("/application/v4/tenant/tenant1", POST).userIdentity(USER_ID)
- .data("{\"athensDomain\":\"domain1\", \"property\":\"property1\"}")
- .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
- new File("tenant-without-applications.json"));
-
- // Create application
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", POST)
- .userIdentity(USER_ID)
- .oktaAccessToken(OKTA_AT).oktaIdentityToken(OKTA_IT),
- new File("instance-reference.json"));
-
- // Add build service to operator role
- addUserToHostedOperatorRole(HostedAthenzIdentities.from(SCREWDRIVER_ID));
-
// POST (deploy) a system application with an application package
- MultiPartStreamer noAppEntity = createApplicationDeployData(Optional.empty(), true);
+ MultiPartStreamer noAppEntity = createApplicationDeployData(Optional.empty());
tester.assertResponse(request("/application/v4/tenant/hosted-vespa/application/routing/environment/prod/region/us-central-1/instance/default/deploy", POST)
.data(noAppEntity)
.userIdentity(HOSTED_VESPA_OPERATOR),
"{\"error-code\":\"BAD_REQUEST\",\"message\":\"Deployment of system applications during a system upgrade is not allowed\"}",
400);
- deploymentTester.controllerTester().upgradeSystem(deploymentTester.controller().readVersionStatus().controllerVersion().get().versionNumber());
+ deploymentTester.controllerTester()
+ .upgradeSystem(deploymentTester.controller().readVersionStatus().controllerVersion().get()
+ .versionNumber());
tester.assertResponse(request("/application/v4/tenant/hosted-vespa/application/routing/environment/prod/region/us-central-1/instance/default/deploy", POST)
- .data(noAppEntity)
- .userIdentity(HOSTED_VESPA_OPERATOR),
- new File("deploy-result.json"));
+ .data(noAppEntity)
+ .userIdentity(HOSTED_VESPA_OPERATOR),
+ new File("deploy-result.json"));
}
@Test
@@ -1113,7 +1099,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
@Test
- public void testErrorResponses() throws Exception {
+ public void testErrorResponses() {
createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID);
// PUT (update) non-existing tenant returns 403 as tenant access cannot be determined when the tenant does not exist
@@ -1223,7 +1209,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
400);
// POST (deploy) an application to legacy deploy path
- MultiPartStreamer entity = createApplicationDeployData(applicationPackageInstance1, true);
+ MultiPartStreamer entity = createApplicationDeployData(applicationPackageInstance1);
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/dev/region/us-east-1/instance/instance1/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
@@ -1330,7 +1316,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
200);
// Deploy to an authorized zone by a user tenant is disallowed
- MultiPartStreamer entity = createApplicationDeployData(applicationPackageDefault, true);
+ MultiPartStreamer entity = createApplicationDeployData(applicationPackageDefault);
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/deploy", POST)
.data(entity)
.userIdentity(USER_ID),
@@ -1437,7 +1423,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
.build();
createTenantAndApplication();
- MultiPartStreamer entity = createApplicationDeployData(applicationPackage, true);
+ MultiPartStreamer entity = createApplicationDeployData(applicationPackage);
// POST (deploy) an application to dev through a deployment job, with user instance and a proper tenant
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/new-user/deploy/dev-us-east-1", POST)
.data(entity)
@@ -1484,7 +1470,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
.build();
// deploy the application to a dev zone. Should fail since the developer is not authorized to launch the service
- MultiPartStreamer entity = createApplicationDeployData(applicationPackage, true);
+ MultiPartStreamer entity = createApplicationDeployData(applicationPackage);
tester.assertResponse(request("/application/v4/tenant/sandbox/application/myapp/instance/default/deploy/dev-us-east-1", POST)
.data(entity)
.userIdentity(developer),
@@ -1646,7 +1632,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
@Test
- public void testServiceView() throws Exception {
+ public void testServiceView() {
createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID);
String serviceApi="/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service";
// Not allowed to request apis not listed in feature flag allowed-service-view-apis. e.g /document/v1
@@ -1713,18 +1699,18 @@ public class ApplicationApiTest extends ControllerContainerTest {
.build();
}
- private MultiPartStreamer createApplicationDeployData(ApplicationPackage applicationPackage, boolean deployDirectly) {
- return createApplicationDeployData(Optional.of(applicationPackage), deployDirectly);
+ private MultiPartStreamer createApplicationDeployData(ApplicationPackage applicationPackage) {
+ return createApplicationDeployData(Optional.of(applicationPackage));
}
- private MultiPartStreamer createApplicationDeployData(Optional<ApplicationPackage> applicationPackage, boolean deployDirectly) {
- return createApplicationDeployData(applicationPackage, Optional.empty(), deployDirectly);
+ private MultiPartStreamer createApplicationDeployData(Optional<ApplicationPackage> applicationPackage) {
+ return createApplicationDeployData(applicationPackage, Optional.empty());
}
private MultiPartStreamer createApplicationDeployData(Optional<ApplicationPackage> applicationPackage,
- Optional<ApplicationVersion> applicationVersion, boolean deployDirectly) {
+ Optional<ApplicationVersion> applicationVersion) {
MultiPartStreamer streamer = new MultiPartStreamer();
- streamer.addJson("deployOptions", deployOptions(deployDirectly, applicationVersion));
+ streamer.addJson("deployOptions", deployOptions(applicationVersion));
applicationPackage.ifPresent(ap -> streamer.addBytes("applicationZip", ap.zippedContent()));
return streamer;
}
@@ -1736,10 +1722,9 @@ public class ApplicationApiTest extends ControllerContainerTest {
.addBytes(EnvironmentResource.APPLICATION_TEST_ZIP, "content".getBytes());
}
- private String deployOptions(boolean deployDirectly, Optional<ApplicationVersion> applicationVersion) {
+ private String deployOptions(Optional<ApplicationVersion> applicationVersion) {
return "{\"vespaVersion\":null," +
- "\"ignoreValidationErrors\":false," +
- "\"deployDirectly\":" + deployDirectly +
+ "\"ignoreValidationErrors\":false" +
applicationVersion.map(version ->
"," +
"\"buildNumber\":" + version.buildNumber().getAsLong() + "," +
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiTest.java
index 8e51f8210c7..b2b5b2286f7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiTest.java
@@ -4,7 +4,6 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.flags.InMemoryFlagSource;
-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.restapi.ContainerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest;
@@ -33,8 +32,6 @@ public class HorizonApiTest extends ControllerContainerCloudTest {
((InMemoryFlagSource) tester.controller().flagSource())
.withBooleanFlag(Flags.ENABLED_HORIZON_DASHBOARD.id(), true);
- tester.controller().serviceRegistry().billingController().setPlan(tenantName, PlanId.from("pay-as-you-go"), true);
-
tester.assertResponse(request("/horizon/v1/config/dashboard/topFolders")
.roles(Set.of(Role.reader(tenantName))),
"", 200);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
index 0a416600b2c..006c3b98a4d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-athenz.json
@@ -1,7 +1,6 @@
{
"isPublic": false,
"isCd": false,
- "enable-public-signup-flow": (ignore),
"hasTrialCapacity": (ignore),
"user": {
"name": "Joe Developer",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
index 4e179ad83c5..4ae55e97baa 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-with-applications-cloud.json
@@ -1,7 +1,6 @@
{
"isPublic": true,
"isCd": false,
- "enable-public-signup-flow": (ignore),
"hasTrialCapacity": true,
"user": {
"name": "Joe Developer",
@@ -14,20 +13,17 @@
"roles": [
"developer",
"reader"
- ],
- "enabled-horizon-dashboard":false
+ ]
},
"tenant1": {
"roles": [
"administrator"
- ],
- "enabled-horizon-dashboard":false
+ ]
},
"tenant2": {
"roles": [
"developer"
- ],
- "enabled-horizon-dashboard":false
+ ]
}
},
"flags": [{"id":"enable-public-signup-flow","rules":[{"value":false}]}]
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
index 7eb445140e7..9f9578e6ed8 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json
@@ -1,7 +1,6 @@
{
"isPublic": (ignore),
"isCd": (ignore),
- "enable-public-signup-flow": (ignore),
"hasTrialCapacity": (ignore),
"user": {
"name": "Joe Developer",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json
index 3c1edab8cfc..2b98a75068a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-trial-capacity-cloud.json
@@ -1,7 +1,6 @@
{
"isPublic": true,
"isCd": false,
- "enable-public-signup-flow": true,
"hasTrialCapacity": false,
"user": {
"name": "Joe Developer",