aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorolaaun <olaa@oath.com>2018-11-09 10:43:04 +0100
committerGitHub <noreply@github.com>2018-11-09 10:43:04 +0100
commita9d8f3fcbb5e348ef1e91aefd7bd5caf4356e533 (patch)
treeaf0a79403c1cd744a5b11183d93b6cb33c062317 /controller-server
parent6253162369e45210be6bdef22cd5a004420304d9 (diff)
Split Organization to two classes. Add contact info for all tenants. Add queue and component in contact info (#7533)
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java31
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java24
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java43
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporter.java25
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java67
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java8
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/AthenzTenant.java16
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Contact.java75
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java21
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/UserTenant.java14
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java29
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java28
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java19
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandlerTest.java12
21 files changed, 228 insertions, 259 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
index cb3f50d08c7..590b18f929d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedTenant.java
@@ -7,7 +7,9 @@ import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
+import com.yahoo.vespa.hosted.controller.tenant.Tenant;
+import com.yahoo.vespa.hosted.controller.tenant.UserTenant;
import java.util.Objects;
import java.util.Optional;
@@ -22,10 +24,11 @@ public class LockedTenant {
private final Lock lock;
private final TenantName name;
- private final AthenzDomain domain;
- private final Property property;
- private final Optional<PropertyId> propertyId;
+ private AthenzDomain domain;
+ private Property property;
+ private Optional<PropertyId> propertyId;
private final Optional<Contact> contact;
+ private final boolean isAthenzTenant;
/**
* Should never be constructed directly.
@@ -37,6 +40,10 @@ public class LockedTenant {
this(lock, tenant.name(), tenant.domain(), tenant.property(), tenant.propertyId(), tenant.contact());
}
+ LockedTenant(UserTenant tenant, Lock lock) {
+ this(lock, tenant.name(), tenant.contact());
+ }
+
private LockedTenant(Lock lock, TenantName name, AthenzDomain domain, Property property,
Optional<PropertyId> propertyId, Optional<Contact> contact) {
this.lock = Objects.requireNonNull(lock, "lock must be non-null");
@@ -45,11 +52,20 @@ public class LockedTenant {
this.property = Objects.requireNonNull(property, "property must be non-null");
this.propertyId = Objects.requireNonNull(propertyId, "propertyId must be non-null");
this.contact = Objects.requireNonNull(contact, "contact must be non-null");
+ this.isAthenzTenant = true;
+ }
+
+ private LockedTenant(Lock lock, TenantName name, Optional<Contact> contact) {
+ this.lock = Objects.requireNonNull(lock, "lock must be non-null");
+ this.name = Objects.requireNonNull(name, "name must be non-null");
+ this.contact = Objects.requireNonNull(contact, "contact must be non-null");
+ this.isAthenzTenant = false;
}
/** Returns a read-only copy of this */
- public AthenzTenant get() {
- return new AthenzTenant(name, domain, property, propertyId, contact);
+ public Tenant get() {
+ if (isAthenzTenant) return new AthenzTenant(name, domain, property, propertyId, contact);
+ else return new UserTenant(name, contact);
}
public LockedTenant with(AthenzDomain domain) {
@@ -65,7 +81,8 @@ public class LockedTenant {
}
public LockedTenant with(Contact contact) {
- return new LockedTenant(lock, name, domain, property, propertyId, Optional.of(contact));
+ if (isAthenzTenant) return new LockedTenant(lock, name, domain, property, propertyId, Optional.of(contact));
+ return new LockedTenant(lock, name, Optional.of(contact));
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
index f0e13349fbf..78099fac34e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java
@@ -102,7 +102,11 @@ public class TenantController {
*/
public void lockIfPresent(TenantName name, Consumer<LockedTenant> action) {
try (Lock lock = lock(name)) {
- athenzTenant(name).map(tenant -> new LockedTenant(tenant, lock)).ifPresent(action);
+ tenant(name).map(tenant -> {
+ tenant = tenant instanceof AthenzTenant ? (AthenzTenant) tenant : (UserTenant) tenant;
+ if (tenant instanceof AthenzTenant) return new LockedTenant((AthenzTenant) tenant, lock);
+ else return new LockedTenant((UserTenant) tenant, lock);
+ }).ifPresent(action);
}
}
@@ -173,7 +177,8 @@ public class TenantController {
/** Update Athenz domain for tenant. Returns the updated tenant which must be explicitly stored */
public LockedTenant withDomain(LockedTenant tenant, AthenzDomain newDomain, OktaAccessToken token) {
- AthenzDomain existingDomain = tenant.get().domain();
+ AthenzTenant athenzTenant = (AthenzTenant) tenant.get();
+ AthenzDomain existingDomain = athenzTenant.domain();
if (existingDomain.equals(newDomain)) return tenant;
Optional<Tenant> existingTenantWithNewDomain = tenantIn(newDomain);
if (existingTenantWithNewDomain.isPresent())
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java
index 219517cfd30..e260848d93a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java
@@ -4,7 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
-import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipIssues;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
@@ -14,7 +14,6 @@ import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.yolean.Exceptions;
import java.time.Duration;
-import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.logging.Level;
@@ -52,9 +51,7 @@ public class ApplicationOwnershipConfirmer extends Maintainer {
try {
Tenant tenant = ownerOf(application.id());
Optional<IssueId> ourIssueId = application.ownershipIssueId();
- ourIssueId = tenant instanceof AthenzTenant
- ? ownershipIssues.confirmOwnership(ourIssueId, application.id(), propertyIdFor((AthenzTenant) tenant))
- : ownershipIssues.confirmOwnership(ourIssueId, application.id(), userFor(tenant));
+ ourIssueId = ownershipIssues.confirmOwnership(ourIssueId, application.id(), userFor(tenant), tenant.contact().orElseThrow(RuntimeException::new));
ourIssueId.ifPresent(issueId -> store(issueId, application.id()));
}
catch (RuntimeException e) { // Catch errors due to wrong data in the controller, or issues client timeout.
@@ -69,12 +66,11 @@ public class ApplicationOwnershipConfirmer extends Maintainer {
for (Application application : controller().applications().asList())
application.ownershipIssueId().ifPresent(issueId -> {
try {
- Optional<PropertyId> propertyId = Optional.of(application.id())
- .map(this::ownerOf)
- .filter(t -> t instanceof AthenzTenant)
- .map(AthenzTenant.class::cast)
- .flatMap(AthenzTenant::propertyId);
- ownershipIssues.ensureResponse(issueId, propertyId);
+ Optional<Contact> contact = Optional.of(application.id())
+ .map(this::ownerOf)
+ .filter(t -> t instanceof AthenzTenant)
+ .flatMap(Tenant::contact);
+ ownershipIssues.ensureResponse(issueId, contact);
}
catch (RuntimeException e) {
log.log(Level.INFO, "Exception caught when attempting to escalate issue with id '" + issueId + "': " + Exceptions.toMessageString(e));
@@ -91,12 +87,6 @@ public class ApplicationOwnershipConfirmer extends Maintainer {
return User.from(tenant.name().value().replaceFirst(Tenant.userPrefix, ""));
}
- protected PropertyId propertyIdFor(AthenzTenant tenant) {
- return tenant.propertyId()
- .orElseThrow(() -> new NoSuchElementException("No PropertyId is listed for non-user tenant " +
- tenant));
- }
-
protected void store(IssueId issueId, ApplicationId applicationId) {
controller().applications().lockIfPresent(applicationId, application ->
controller().applications().store(application.withOwnershipIssueId(issueId)));
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java
index bf5743e2d3c..8bffa455b7e 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java
@@ -1,23 +1,21 @@
// 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.maintenance;
+import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.ContactRetriever;
import com.yahoo.config.provision.SystemName;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.hosted.controller.Controller;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.Organization;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.yolean.Exceptions;
import java.time.Duration;
import java.util.EnumSet;
-import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
/**
* Periodically fetch and store contact information for tenants.
@@ -28,23 +26,20 @@ public class ContactInformationMaintainer extends Maintainer {
private static final Logger log = Logger.getLogger(ContactInformationMaintainer.class.getName());
- private final Organization organization;
+ private final ContactRetriever contactRetriever;
- public ContactInformationMaintainer(Controller controller, Duration interval, JobControl jobControl, Organization organization) {
+ public ContactInformationMaintainer(Controller controller, Duration interval, JobControl jobControl, ContactRetriever contactRetriever) {
super(controller, interval, jobControl, null, EnumSet.of(SystemName.cd, SystemName.main));
- this.organization = Objects.requireNonNull(organization, "organization must be non-null");
+ this.contactRetriever = Objects.requireNonNull(contactRetriever, "organization must be non-null");
}
@Override
protected void maintain() {
- for (Tenant t : controller().tenants().asList()) {
- if (!(t instanceof AthenzTenant)) continue; // No contact information for non-Athenz tenants
- AthenzTenant tenant = (AthenzTenant) t;
- if (!tenant.propertyId().isPresent()) continue; // Can only update contact information if property ID is known
- try {
- findContact(tenant).ifPresent(contact -> {
- controller().tenants().lockIfPresent(t.name(), lockedTenant -> controller().tenants().store(lockedTenant.with(contact)));
- });
+ for (Tenant tenant : controller().tenants().asList()) {
+ try{
+ Optional<PropertyId> tenantPropertyId = tenant instanceof AthenzTenant ? ((AthenzTenant) tenant).propertyId() : Optional.empty();
+ Contact contact = contactRetriever.getContact(tenantPropertyId);
+ controller().tenants().lockIfPresent(tenant.name(), lockedTenant -> controller().tenants().store(lockedTenant.with(contact)));
} catch (Exception e) {
log.log(LogLevel.WARNING, "Failed to update contact information for " + tenant + ": " +
Exceptions.toMessageString(e) + ". Retrying in " +
@@ -53,21 +48,5 @@ public class ContactInformationMaintainer extends Maintainer {
}
}
- /** Find contact information for given tenant */
- private Optional<Contact> findContact(AthenzTenant tenant) {
- if (!tenant.propertyId().isPresent()) {
- return Optional.empty();
- }
- List<List<String>> persons = organization.contactsFor(tenant.propertyId().get())
- .stream()
- .map(personList -> personList.stream()
- .map(User::displayName)
- .collect(Collectors.toList()))
- .collect(Collectors.toList());
- return Optional.of(new Contact(organization.contactsUri(tenant.propertyId().get()),
- organization.propertyUri(tenant.propertyId().get()),
- organization.issueCreationUri(tenant.propertyId().get()),
- persons));
- }
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
index 7b17f38bd78..f6978ef70ac 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
@@ -4,12 +4,12 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.component.AbstractComponent;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.ContactRetriever;
import com.yahoo.vespa.hosted.controller.authority.config.ApiAuthorityConfig;
import com.yahoo.vespa.hosted.controller.api.integration.chef.Chef;
import com.yahoo.vespa.hosted.controller.api.integration.dns.NameService;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryClientInterface;
import com.yahoo.vespa.hosted.controller.api.integration.organization.DeploymentIssues;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.Organization;
import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipIssues;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.maintenance.config.MaintainerConfig;
@@ -54,7 +54,7 @@ public class ControllerMaintenance extends AbstractComponent {
JobControl jobControl, Metric metric, Chef chefClient,
DeploymentIssues deploymentIssues, OwnershipIssues ownershipIssues,
NameService nameService, NodeRepositoryClientInterface nodeRepositoryClient,
- Organization organization) {
+ ContactRetriever contactRetriever) {
Duration maintenanceInterval = Duration.ofMinutes(maintainerConfig.intervalMinutes());
this.jobControl = jobControl;
deploymentExpirer = new DeploymentExpirer(controller, maintenanceInterval, jobControl);
@@ -73,7 +73,7 @@ public class ControllerMaintenance extends AbstractComponent {
jobRunner = new JobRunner(controller, Duration.ofMinutes(2), jobControl);
osUpgraders = osUpgraders(controller, jobControl);
osVersionStatusUpdater = new OsVersionStatusUpdater(controller, maintenanceInterval, jobControl);
- contactInformationMaintainer = new ContactInformationMaintainer(controller, Duration.ofHours(12), jobControl, organization);
+ contactInformationMaintainer = new ContactInformationMaintainer(controller, Duration.ofHours(12), jobControl, contactRetriever);
}
public Upgrader upgrader() { return upgrader; }
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporter.java
index 1745e013a40..13733b32d86 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporter.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporter.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.DeploymentIssues;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
@@ -18,7 +19,6 @@ import com.yahoo.yolean.Exceptions;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
-import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
@@ -113,20 +113,13 @@ public class DeploymentIssueReporter extends Maintainer {
return User.from(tenant.name().value().replaceFirst(Tenant.userPrefix, ""));
}
- private PropertyId propertyIdFor(AthenzTenant tenant) {
- return tenant.propertyId()
- .orElseThrow(() -> new NoSuchElementException("No PropertyId is listed for non-user tenant " +
- tenant));
- }
-
/** File an issue for applicationId, if it doesn't already have an open issue associated with it. */
private void fileDeploymentIssueFor(ApplicationId applicationId) {
try {
Tenant tenant = ownerOf(applicationId);
+ User asignee = userFor(tenant);
Optional<IssueId> ourIssueId = controller().applications().require(applicationId).deploymentJobs().issueId();
- IssueId issueId = tenant instanceof AthenzTenant
- ? deploymentIssues.fileUnlessOpen(ourIssueId, applicationId, propertyIdFor((AthenzTenant) tenant))
- : deploymentIssues.fileUnlessOpen(ourIssueId, applicationId, userFor(tenant));
+ IssueId issueId = deploymentIssues.fileUnlessOpen(ourIssueId, applicationId, asignee, tenant.contact().get());
store(applicationId, issueId);
}
catch (RuntimeException e) { // Catch errors due to wrong data in the controller, or issues client timeout.
@@ -138,12 +131,11 @@ public class DeploymentIssueReporter extends Maintainer {
private void escalateInactiveDeploymentIssues(Collection<Application> applications) {
applications.forEach(application -> application.deploymentJobs().issueId().ifPresent(issueId -> {
try {
- Optional<PropertyId> propertyId = Optional.of(application.id())
- .map(this::ownerOf)
- .filter(t -> t instanceof AthenzTenant)
- .map(AthenzTenant.class::cast)
- .flatMap(AthenzTenant::propertyId);
- deploymentIssues.escalateIfInactive(issueId, propertyId, maxInactivity);
+ AthenzTenant tenant = Optional.of(application.id())
+ .map(this::ownerOf)
+ .filter(t -> t instanceof AthenzTenant)
+ .map(AthenzTenant.class::cast).orElseThrow(RuntimeException::new);
+ deploymentIssues.escalateIfInactive(issueId, maxInactivity, tenant.contact());
}
catch (RuntimeException e) {
log.log(Level.INFO, "Exception caught when attempting to escalate issue with id '" + issueId + "': " + Exceptions.toMessageString(e));
@@ -155,5 +147,4 @@ public class DeploymentIssueReporter extends Maintainer {
controller().applications().lockIfPresent(id, application ->
controller().applications().store(application.withDeploymentIssueId(issueId)));
}
-
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
index 631aaa5a909..9c52d7a2244 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
@@ -280,7 +280,7 @@ public class CuratorDb {
// -------------- Tenant --------------------------------------------------
- public void writeTenant(UserTenant tenant) {
+ public void writeTenant(Tenant tenant) {
curator.set(tenantPath(tenant.name()), asJson(tenantSerializer.toSlime(tenant)));
}
@@ -288,10 +288,6 @@ public class CuratorDb {
return readSlime(tenantPath(name)).map(tenantSerializer::userTenantFrom);
}
- public void writeTenant(AthenzTenant tenant) {
- curator.set(tenantPath(tenant.name()), asJson(tenantSerializer.toSlime(tenant)));
- }
-
public Optional<AthenzTenant> readAthenzTenant(TenantName name) {
return readSlime(tenantPath(name)).map(tenantSerializer::athenzTenantFrom);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
index 28400b85306..245cb0f4dae 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializer.java
@@ -12,7 +12,8 @@ import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
+import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.tenant.UserTenant;
import java.net.URI;
@@ -37,8 +38,15 @@ public class TenantSerializer {
private static final String issueTrackerUrlField = "issueTrackerUrl";
private static final String personsField = "persons";
private static final String personField = "person";
+ private static final String queueField = "queue";
+ private static final String componentField = "component";
- public Slime toSlime(AthenzTenant tenant) {
+ public Slime toSlime(Tenant tenant) {
+ if (tenant instanceof AthenzTenant) return toSlime((AthenzTenant) tenant);
+ return toSlime((UserTenant) tenant);
+ }
+
+ private Slime toSlime(AthenzTenant tenant) {
Slime slime = new Slime();
Cursor root = slime.setObject();
root.setString(nameField, tenant.name().value());
@@ -46,26 +54,20 @@ public class TenantSerializer {
root.setString(propertyField, tenant.property().id());
tenant.propertyId().ifPresent(propertyId -> root.setString(propertyIdField, propertyId.id()));
tenant.contact().ifPresent(contact -> {
- Cursor contactObject = root.setObject(contactField);
- contactObject.setString(contactUrlField, contact.url().toString());
- contactObject.setString(propertyUrlField, contact.propertyUrl().toString());
- contactObject.setString(issueTrackerUrlField, contact.issueTrackerUrl().toString());
- Cursor personsArray = contactObject.setArray(personsField);
- contact.persons().forEach(personList -> {
- Cursor personArray = personsArray.addArray();
- personList.forEach(person -> {
- Cursor personObject = personArray.addObject();
- personObject.setString(personField, person);
- });
- });
+ Cursor contactCursor = root.setObject(contactField);
+ writeContact(contact, contactCursor);
});
return slime;
}
- public Slime toSlime(UserTenant tenant) {
+ private Slime toSlime(UserTenant tenant) {
Slime slime = new Slime();
Cursor root = slime.setObject();
root.setString(nameField, tenant.name().value());
+ tenant.contact().ifPresent(contact -> {
+ Cursor contactCursor = root.setObject(contactField);
+ writeContact(contact, contactCursor);
+ });
return slime;
}
@@ -82,17 +84,42 @@ public class TenantSerializer {
public UserTenant userTenantFrom(Slime slime) {
Inspector root = slime.get();
TenantName name = TenantName.from(root.field(nameField).asString());
- return new UserTenant(name);
+ Optional<Contact> contact = contactFrom(root.field(contactField));
+ return new UserTenant(name, contact);
}
private Optional<Contact> contactFrom(Inspector object) {
if (!object.valid()) {
return Optional.empty();
}
- return Optional.of(new Contact(URI.create(object.field(contactUrlField).asString()),
- URI.create(object.field(propertyUrlField).asString()),
- URI.create(object.field(issueTrackerUrlField).asString()),
- personsFrom(object.field(personsField))));
+ URI contactUrl = URI.create(object.field(contactUrlField).asString());
+ URI propertyUrl = URI.create(object.field(propertyUrlField).asString());
+ URI issueTrackerUrl = URI.create(object.field(issueTrackerUrlField).asString());
+ List<List<String>> persons = personsFrom(object.field(personsField));
+ String queue = object.field(queueField).asString();
+ Optional<String> component = object.field(componentField).valid() ? Optional.of(object.field(componentField).asString()) : Optional.empty();
+ return Optional.of(new Contact(contactUrl,
+ propertyUrl,
+ issueTrackerUrl,
+ persons,
+ queue,
+ component));
+ }
+
+ private void writeContact(Contact contact, Cursor contactCursor) {
+ contactCursor.setString(contactUrlField, contact.url().toString());
+ contactCursor.setString(propertyUrlField, contact.propertyUrl().toString());
+ contactCursor.setString(issueTrackerUrlField, contact.issueTrackerUrl().toString());
+ Cursor personsArray = contactCursor.setArray(personsField);
+ contact.persons().forEach(personList -> {
+ Cursor personArray = personsArray.addArray();
+ personList.forEach(person -> {
+ Cursor personObject = personArray.addObject();
+ personObject.setString(personField, person);
+ });
+ });
+ contactCursor.setString(queueField, contact.queue());
+ contact.component().ifPresent(component -> contactCursor.setString(componentField, component));
}
private List<List<String>> personsFrom(Inspector array) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java
index 7651381b810..cf9db8fd992 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java
@@ -17,7 +17,7 @@ import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse;
import com.yahoo.vespa.hosted.controller.restapi.StringResponse;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.yolean.Exceptions;
import java.io.IOException;
@@ -117,6 +117,8 @@ public class ContactInfoHandler extends LoggingRequestHandler {
sublist.addString(person);
}
}
+ cursor.setString("queue", contact.queue());
+ contact.component().ifPresent(component -> cursor.setString("component", component));
return slime;
}
@@ -125,6 +127,8 @@ public class ContactInfoHandler extends LoggingRequestHandler {
URI propertyUrl = URI.create(inspector.field("propertyUrl").asString());
URI url = URI.create(inspector.field("url").asString());
URI issueTrackerUrl = URI.create(inspector.field("issueTrackerUrl").asString());
+ String queue = inspector.field("queue").asString();
+ Optional<String> component = inspector.field("component").valid() ? Optional.of(inspector.field("component").asString()) : Optional.empty();
Inspector personInspector = inspector.field("persons");
List<List<String>> personList = new ArrayList<>();
personInspector.traverse((ArrayTraverser) (index, entry) -> {
@@ -134,7 +138,7 @@ public class ContactInfoHandler extends LoggingRequestHandler {
});
personList.add(subList);
});
- return new Contact(url, propertyUrl, issueTrackerUrl, personList);
+ return new Contact(url, propertyUrl, issueTrackerUrl, personList, queue, component);
}
}
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
index 8cbb4e06aca..3879e7f29ca 100644
--- 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
@@ -5,6 +5,7 @@ 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.util.Objects;
import java.util.Optional;
@@ -19,7 +20,7 @@ public class AthenzTenant extends Tenant {
private final AthenzDomain domain;
private final Property property;
private final Optional<PropertyId> propertyId;
- private final Optional<Contact> contact;
+
/**
* This should only be used by serialization.
@@ -27,11 +28,10 @@ public class AthenzTenant extends Tenant {
* */
public AthenzTenant(TenantName name, AthenzDomain domain, Property property, Optional<PropertyId> propertyId,
Optional<Contact> contact) {
- super(name);
+ super(name, Objects.requireNonNull(contact, "contact must be non-null"));
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");
- this.contact = Objects.requireNonNull(contact, "contact must be non-null");
}
/** Property name of this tenant */
@@ -44,11 +44,6 @@ public class AthenzTenant extends Tenant {
return propertyId;
}
- /** Contact information for this, if any */
- public Optional<Contact> contact() {
- return contact;
- }
-
/** Athenz domain of this tenant */
public AthenzDomain domain() {
return domain;
@@ -70,6 +65,11 @@ public class AthenzTenant extends Tenant {
return new AthenzTenant(requireName(requireNoPrefix(name)), domain, property, propertyId, Optional.empty());
}
+ public static AthenzTenant create(TenantName name, AthenzDomain domain, Property property,
+ Optional<PropertyId> propertyId, Optional<Contact> contact) {
+ return new AthenzTenant(requireName(requireNoPrefix(name)), domain, property, propertyId, contact);
+ }
+
private static TenantName requireNoPrefix(TenantName name) {
if (name.value().startsWith(Tenant.userPrefix)) {
throw new IllegalArgumentException("Athenz tenant name cannot have prefix '" + Tenant.userPrefix + "'");
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Contact.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Contact.java
deleted file mode 100644
index e13b0f982da..00000000000
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Contact.java
+++ /dev/null
@@ -1,75 +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.google.common.collect.ImmutableList;
-
-import java.net.URI;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Contact information for a tenant.
- *
- * @author mpolden
- */
-public class Contact {
-
- private final URI url;
- private final URI propertyUrl;
- private final URI issueTrackerUrl;
- private final List<List<String>> persons;
-
- public Contact(URI url, URI propertyUrl, URI issueTrackerUrl, List<List<String>> persons) {
- this.propertyUrl = Objects.requireNonNull(propertyUrl, "propertyUrl must be non-null");
- this.url = Objects.requireNonNull(url, "url must be non-null");
- this.issueTrackerUrl = Objects.requireNonNull(issueTrackerUrl, "issueTrackerUrl must be non-null");
- this.persons = ImmutableList.copyOf(Objects.requireNonNull(persons, "persons must be non-null"));
- }
-
- /** URL to this */
- public URI url() {
- return url;
- }
-
- /** URL to information about this property */
- public URI propertyUrl() {
- return propertyUrl;
- }
-
- /** URL to this contacts's issue tracker */
- public URI issueTrackerUrl() {
- return issueTrackerUrl;
- }
-
- /** Nested list of persons representing this. First level represents that person's rank in the corporate dystopia. */
- public List<List<String>> persons() {
- return persons;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Contact contact = (Contact) o;
- return Objects.equals(url, contact.url) &&
- Objects.equals(propertyUrl, contact.propertyUrl) &&
- Objects.equals(issueTrackerUrl, contact.issueTrackerUrl) &&
- Objects.equals(persons, contact.persons);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(url, propertyUrl, issueTrackerUrl, persons);
- }
-
- @Override
- public String toString() {
- return "Contact{" +
- "url=" + url +
- ", propertyUrl=" + propertyUrl +
- ", issueTrackerUrl=" + issueTrackerUrl +
- ", persons=" + persons +
- '}';
- }
-
-}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java
index aac3fa20d11..98950ca2632 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Tenant.java
@@ -3,8 +3,11 @@ package com.yahoo.vespa.hosted.controller.tenant;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
+import javax.swing.text.html.Option;
import java.util.Objects;
+import java.util.Optional;
/**
* A tenant in hosted Vespa.
@@ -17,15 +20,31 @@ public abstract class Tenant {
private final TenantName name;
- Tenant(TenantName name) {
+ private Optional<Contact> contact;
+
+ Tenant(TenantName name, Optional<Contact> contact) {
this.name = name;
+ this.contact = contact;
}
+ /*Tenant(TenantName name) {
+ this(name, Optional.empty());
+ }*/
+
/** Name of this tenant */
public TenantName name() {
return name;
}
+ public Optional<Contact> contact() {
+ return contact;
+ }
+
+ public Tenant withContact(Optional<Contact> contact) {
+ this.contact = contact;
+ return this;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/UserTenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/UserTenant.java
index e110600639b..47e5580fbe4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/UserTenant.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/tenant/UserTenant.java
@@ -2,6 +2,9 @@
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.util.Optional;
/**
* Represents an user tenant in hosted Vespa.
@@ -14,8 +17,12 @@ public class UserTenant extends Tenant {
* This should only be used by serialization.
* Use {@link #create(String)}.
* */
+ public UserTenant(TenantName name, Optional<Contact> contact) {
+ super(name, contact);
+ }
+
public UserTenant(TenantName name) {
- super(name);
+ super(name, Optional.empty());
}
/** Returns true if this is the tenant for the given user name */
@@ -34,6 +41,11 @@ public class UserTenant extends Tenant {
return new UserTenant(requireName(requireUser(name)));
}
+ public static UserTenant create(String username, Optional<Contact> contact) {
+ TenantName name = TenantName.from(username);
+ return new UserTenant(requireName(requireUser(name)), contact);
+ }
+
/** Normalize given username. E.g. foo_bar becomes by-foo-bar */
public static String normalizeUser(String username) {
int offset = 0;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
index 8994c68acf3..639511959df 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java
@@ -23,7 +23,9 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.MemoryNameService;
import com.yahoo.vespa.hosted.controller.api.integration.entity.EntityService;
import com.yahoo.vespa.hosted.controller.api.integration.entity.MemoryEntityService;
import com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.MockIssueHandler;
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockRunDataStore;
@@ -78,7 +80,8 @@ public final class ControllerTester {
private final MockBuildService buildService;
private final MetricsServiceMock metricsService;
private final RoutingGeneratorMock routingGenerator;
- private final MockOrganization organization;
+ private final MockContactRetriever contactRetriever;
+ private final MockIssueHandler issueHandler;
private Controller controller;
@@ -88,7 +91,7 @@ public final class ControllerTester {
new ZoneRegistryMock(), new GitHubMock(), curatorDb, rotationsConfig,
new MemoryNameService(), new ArtifactRepositoryMock(), new ApplicationStoreMock(),
new MemoryEntityService(), new MockBuildService(),
- metricsService, new RoutingGeneratorMock(), new MockOrganization(clock));
+ metricsService, new RoutingGeneratorMock(), new MockContactRetriever(), new MockIssueHandler(clock));
}
public ControllerTester(ManualClock clock) {
@@ -114,7 +117,7 @@ public final class ControllerTester {
ApplicationStoreMock appStoreMock,
EntityService entityService, MockBuildService buildService,
MetricsServiceMock metricsService, RoutingGeneratorMock routingGenerator,
- MockOrganization organization) {
+ MockContactRetriever contactRetriever, MockIssueHandler issueHandler) {
this.athenzDb = athenzDb;
this.clock = clock;
this.configServer = configServer;
@@ -129,7 +132,8 @@ public final class ControllerTester {
this.buildService = buildService;
this.metricsService = metricsService;
this.routingGenerator = routingGenerator;
- this.organization = organization;
+ this.contactRetriever = contactRetriever;
+ this.issueHandler = issueHandler;
this.controller = createController(curator, rotationsConfig, configServer, clock, gitHub, zoneRegistry,
athenzDb, nameService, artifactRepository, appStoreMock, entityService, buildService,
metricsService, routingGenerator);
@@ -178,8 +182,8 @@ public final class ControllerTester {
public RoutingGeneratorMock routingGenerator() { return routingGenerator; }
- public MockOrganization organization() {
- return organization;
+ public MockContactRetriever contactRetriever() {
+ return contactRetriever;
}
/** Create a new controller instance. Useful to verify that controller state is rebuilt from persistence */
@@ -240,19 +244,23 @@ public final class ControllerTester {
return domain;
}
- public TenantName createTenant(String tenantName, String domainName, Long propertyId) {
+ public TenantName createTenant(String tenantName, String domainName, Long propertyId, Optional<Contact> contact) {
TenantName name = TenantName.from(tenantName);
Optional<Tenant> existing = controller().tenants().tenant(name);
if (existing.isPresent()) return name;
AthenzTenant tenant = AthenzTenant.create(name, createDomain(domainName), new Property("app1Property"),
Optional.ofNullable(propertyId)
.map(Object::toString)
- .map(PropertyId::new));
+ .map(PropertyId::new), contact);
controller().tenants().create(tenant, new OktaAccessToken("okta-token"));
assertNotNull(controller().tenants().tenant(name));
return name;
}
+ public TenantName createTenant(String tenantName, String domainName, Long propertyId) {
+ return createTenant(tenantName, domainName, propertyId, Optional.empty());
+ }
+
public Application createApplication(TenantName tenant, String applicationName, String instanceName, long projectId) {
ApplicationId applicationId = ApplicationId.from(tenant.value(), applicationName, instanceName);
controller().applications().createApplication(applicationId, Optional.of(new OktaAccessToken("okta-token")));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java
index 2694e205a68..62653f29518 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java
@@ -4,7 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.hosted.controller.Application;
-import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipIssues;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
@@ -40,18 +40,19 @@ public class ApplicationOwnershipConfirmerTest {
@Test
public void testConfirmation() {
- TenantName property = tester.controllerTester().createTenant("property", "domain", 1L);
+ Optional<Contact> contact = Optional.of(tester.controllerTester().contactRetriever().contact());
+ TenantName property = tester.controllerTester().createTenant("property", "domain", 1L, contact);
tester.createAndDeploy(property, "application", 1, "default");
Supplier<Application> propertyApp = () -> tester.controller().applications().require(ApplicationId.from("property", "application", "default"));
- UserTenant user = UserTenant.create("by-user");
+ UserTenant user = UserTenant.create("by-user", contact);
tester.controller().tenants().create(user);
tester.createAndDeploy(user.name(), "application", 2, "default");
Supplier<Application> userApp = () -> tester.controller().applications().require(ApplicationId.from("by-user", "application", "default"));
assertFalse("No issue is initially stored for a new application.", propertyApp.get().ownershipIssueId().isPresent());
assertFalse("No issue is initially stored for a new application.", userApp.get().ownershipIssueId().isPresent());
- assertFalse("No escalation has been attempted for a new application", issues.escalatedForProperty || issues.escalatedForUser);
+ assertFalse("No escalation has been attempted for a new application", issues.escalatedToContact || issues.escalatedToTerminator);
// Set response from the issue mock, which will be obtained by the maintainer on issue filing.
Optional<IssueId> issueId = Optional.of(IssueId.from("1"));
@@ -68,7 +69,8 @@ public class ApplicationOwnershipConfirmerTest {
assertEquals("Confirmation issue has been filed for property owned application.", issueId, propertyApp.get().ownershipIssueId());
assertEquals("Confirmation issue has been filed for user owned application.", issueId, userApp.get().ownershipIssueId());
- assertTrue("Both applications have had their responses ensured.", issues.escalatedForProperty && issues.escalatedForUser);
+ assertTrue(issues.escalatedToTerminator);
+ assertTrue("Both applications have had their responses ensured.", issues.escalatedToContact && issues.escalatedToTerminator);
// No new issue is created, so return empty now.
issues.response = Optional.empty();
@@ -99,23 +101,18 @@ public class ApplicationOwnershipConfirmerTest {
private class MockOwnershipIssues implements OwnershipIssues {
private Optional<IssueId> response;
- private boolean escalatedForProperty = false;
- private boolean escalatedForUser = false;
+ private boolean escalatedToContact = false;
+ private boolean escalatedToTerminator = false;
@Override
- public Optional<IssueId> confirmOwnership(Optional<IssueId> issueId, ApplicationId applicationId, PropertyId propertyId) {
+ public Optional<IssueId> confirmOwnership(Optional<IssueId> issueId, ApplicationId applicationId, User asignee, Contact contact) {
return response;
}
@Override
- public Optional<IssueId> confirmOwnership(Optional<IssueId> issueId, ApplicationId applicationId, User owner) {
- return response;
- }
-
- @Override
- public void ensureResponse(IssueId issueId, Optional<PropertyId> propertyId) {
- if (propertyId.isPresent()) escalatedForProperty = true;
- else escalatedForUser = true;
+ public void ensureResponse(IssueId issueId, Optional<Contact> contact) {
+ if (contact.isPresent()) escalatedToContact = true;
+ else escalatedToTerminator = true;
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java
index cbaa37b15e3..6a7096dbfae 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java
@@ -6,7 +6,7 @@ import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import org.junit.Before;
import org.junit.Test;
@@ -15,6 +15,7 @@ import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -35,7 +36,7 @@ public class ContactInformationMaintainerTest {
tester = new ControllerTester();
maintainer = new ContactInformationMaintainer(tester.controller(), Duration.ofDays(1),
new JobControl(tester.controller().curator()),
- tester.organization());
+ tester.contactRetriever());
}
@Test
@@ -55,14 +56,7 @@ public class ContactInformationMaintainerTest {
private void registerContact(long propertyId, Contact contact) {
PropertyId p = new PropertyId(String.valueOf(propertyId));
- tester.organization().addProperty(p)
- .setContactsUrl(p, contact.url())
- .setIssueUrl(p, contact.issueTrackerUrl())
- .setPropertyUrl(p, contact.propertyUrl())
- .setContactsFor(p, contact.persons().stream().map(persons -> persons.stream()
- .map(User::from)
- .collect(Collectors.toList()))
- .collect(Collectors.toList()));
+ tester.contactRetriever().addContact(p, contact);
}
private static Contact testContact() {
@@ -71,7 +65,9 @@ public class ContactInformationMaintainerTest {
URI propertyUrl = URI.create("http://property1.test");
List<List<String>> persons = Arrays.asList(Collections.singletonList("alice"),
Collections.singletonList("bob"));
- return new Contact(contactUrl, propertyUrl, issueTrackerUrl, persons);
+ String queue = "queue";
+ Optional<String> component = Optional.empty();
+ return new Contact(contactUrl, propertyUrl, issueTrackerUrl, persons, queue, component);
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
index dcfcb813de6..e97376d1f66 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
@@ -5,6 +5,7 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Environment;
import com.yahoo.vespa.hosted.controller.Application;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
@@ -18,6 +19,7 @@ import org.junit.Test;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionCorpUsEast1;
@@ -70,6 +72,11 @@ public class DeploymentIssueReporterTest {
tester.upgradeSystem(Version.fromString("6.2"));
+ Optional<Contact> contact = Optional.of(tester.controllerTester().contactRetriever().contact());
+ tester.controllerTester().createTenant("tenant1", "domain1", 1L, contact);
+ tester.controllerTester().createTenant("tenant2", "domain2", 1L, contact);
+ tester.controllerTester().createTenant("tenant3", "domain3", 1L, contact);
+
// Create and deploy one application for each of three tenants.
Application app1 = tester.createApplication("application1", "tenant1", projectId1, propertyId1);
Application app2 = tester.createApplication("application2", "tenant2", projectId2, propertyId2);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
index 60ff556dca4..f3790e6d291 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/TenantSerializerTest.java
@@ -6,7 +6,7 @@ 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.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import com.yahoo.vespa.hosted.controller.tenant.UserTenant;
import org.junit.Test;
@@ -57,24 +57,30 @@ public class TenantSerializerTest {
new AthenzDomain("domain1"),
new Property("property1"),
Optional.of(new PropertyId("1")),
- Optional.of(new Contact(
- URI.create("http://contact1.test"),
- URI.create("http://property1.test"),
- URI.create("http://issue-tracker-1.test"),
- Arrays.asList(
- Collections.singletonList("person1"),
- Collections.singletonList("person2")
- )
- )));
+ Optional.of(contact()));
AthenzTenant serialized = serializer.athenzTenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.contact(), serialized.contact());
}
@Test
public void user_tenant() {
- UserTenant tenant = UserTenant.create("by-foo");
+ UserTenant tenant = UserTenant.create("by-foo", Optional.of(contact()));
UserTenant serialized = serializer.userTenantFrom(serializer.toSlime(tenant));
assertEquals(tenant.name(), serialized.name());
+ assertEquals(contact(), serialized.contact().get());
}
+ private Contact contact() {
+ return new Contact(
+ URI.create("http://contact1.test"),
+ URI.create("http://property1.test"),
+ URI.create("http://issue-tracker-1.test"),
+ Arrays.asList(
+ Collections.singletonList("person1"),
+ Collections.singletonList("person2")
+ ),
+ "queue",
+ Optional.empty()
+ );
+ }
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
index 6044dd7b8f8..e908777a8b0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
@@ -71,7 +71,8 @@ public class ControllerContainerTest {
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.MockRunDataStore'/>\n" +
- " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockIssueHandler'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.ConfigServerMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.NodeRepositoryClientMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.ZoneRegistryMock'/>\n" +
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 43d10484335..8b260765423 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
@@ -32,8 +32,7 @@ import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Change;
@@ -58,7 +57,7 @@ import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester;
import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest;
import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
+import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -1314,8 +1313,8 @@ public class ApplicationApiTest extends ControllerContainerTest {
return (MetricsServiceMock) tester.container().components().getComponent(MetricsServiceMock.class.getName());
}
- private MockOrganization organization() {
- return (MockOrganization) tester.container().components().getComponent(MockOrganization.class.getName());
+ private MockContactRetriever contactRetriever() {
+ return (MockContactRetriever) tester.container().components().getComponent(MockContactRetriever.class.getName());
}
private void setZoneInRotation(String rotationName, ZoneId zone) {
@@ -1341,18 +1340,14 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
private void updateContactInformation() {
- Contact contact = new Contact(URI.create("www.contacts.tld/1234"), URI.create("www.properties.tld/1234"), URI.create("www.issues.tld/1234"), Arrays.asList(Arrays.asList("alice"), Arrays.asList("bob")));
+ Contact contact = new Contact(URI.create("www.contacts.tld/1234"), URI.create("www.properties.tld/1234"), URI.create("www.issues.tld/1234"), Arrays.asList(Arrays.asList("alice"), Arrays.asList("bob")), "queue", Optional.empty());
tester.controller().tenants().lockIfPresent(TenantName.from("tenant2"), lockedTenant -> tester.controller().tenants().store(lockedTenant.with(contact)));
}
private void registerContact(long propertyId) {
PropertyId p = new PropertyId(String.valueOf(propertyId));
- organization().addProperty(p)
- .setIssueUrl(p, URI.create("www.issues.tld/" + p.id()))
- .setContactsUrl(p, URI.create("www.contacts.tld/" + p.id()))
- .setPropertyUrl(p, URI.create("www.properties.tld/" + p.id()))
- .setContactsFor(p, Arrays.asList(Collections.singletonList(User.from("alice")),
- Collections.singletonList(User.from("bob"))));
+ contactRetriever().addContact(p, new Contact(URI.create("www.issues.tld/" + p.id()), URI.create("www.contacts.tld/" + p.id()), URI.create("www.properties.tld/" + p.id()), Arrays.asList(Collections.singletonList("alice"),
+ Collections.singletonList("bob")), "queue", Optional.empty()));
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandlerTest.java
index 459b3a35f85..24506fda31a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandlerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandlerTest.java
@@ -2,17 +2,11 @@ package com.yahoo.vespa.hosted.controller.restapi.contactinfo;
import com.yahoo.application.container.handler.Request;
import com.yahoo.application.container.handler.Response;
-import com.yahoo.slime.Slime;
-import com.yahoo.vespa.config.SlimeUtils;
import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest;
-import com.yahoo.vespa.hosted.controller.tenant.Contact;
import org.junit.Before;
import org.junit.Test;
-import java.net.URI;
-import java.util.Arrays;
-
import static org.junit.Assert.*;
public class ContactInfoHandlerTest extends ControllerContainerTest {
@@ -25,7 +19,7 @@ public class ContactInfoHandlerTest extends ControllerContainerTest {
}
@Test
- public void testGettingAndFeedingContactInfo() throws Exception {
+ public void testGettingAndFeedingContactInfo() {
tester.createApplication();
// No contact information available yet
@@ -33,8 +27,8 @@ public class ContactInfoHandlerTest extends ControllerContainerTest {
assertResponse(new Request("http://localhost:8080/contactinfo/v1/tenant/tenant1"), 404, notFoundMessage);
// Feed contact information for tenant1
- String contactInfo = "{\"url\":\"https://url:4444/\",\"issueTrackerUrl\":\"https://issueTrackerUrl:4444/\",\"propertyUrl\":\"https://propertyUrl:4444/\",\"persons\":[[\"foo\",\"bar\"]]}";
- String expectedResponseMessage = "Added contact info for tenant1 - Contact{url=https://url:4444/, propertyUrl=https://propertyUrl:4444/, issueTrackerUrl=https://issueTrackerUrl:4444/, persons=[[foo, bar]]}";
+ String contactInfo = "{\"url\":\"https://url:4444/\",\"issueTrackerUrl\":\"https://issueTrackerUrl:4444/\",\"propertyUrl\":\"https://propertyUrl:4444/\",\"persons\":[[\"foo\",\"bar\"]],\"queue\":\"queue\",\"component\":\"component\"}";
+ String expectedResponseMessage = "Added contact info for tenant1 - Contact{url=https://url:4444/, propertyUrl=https://propertyUrl:4444/, issueTrackerUrl=https://issueTrackerUrl:4444/, persons=[[foo, bar]], queue=queue, component=component}";
assertResponse(new Request("http://localhost:8080/contactinfo/v1/tenant/tenant1", contactInfo, Request.Method.POST), 200, expectedResponseMessage);
// Get contact information for tenant1