diff options
author | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2017-10-25 11:28:41 +0200 |
---|---|---|
committer | Jon Marius Venstad <jvenstad@yahoo-inc.com> | 2017-10-25 11:28:41 +0200 |
commit | 613ffaeca6ee5de1e6284468a7ce043ce6c73fd4 (patch) | |
tree | b141791c09e9558a6cef604f5066fae7d841f156 | |
parent | 8c34ea2b1e8b7e255571f12fd5c85942edd4503a (diff) |
Expose property relevant URIs and contact lists at tenant/{tenant}/property
5 files changed, 73 insertions, 15 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/MockOrganization.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/MockOrganization.java index 51bba7bb52c..dc3589a69ae 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/MockOrganization.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/MockOrganization.java @@ -1,5 +1,6 @@ package com.yahoo.vespa.hosted.controller.api.integration.organization; +import com.google.inject.Inject; import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId; import java.net.URI; @@ -20,6 +21,12 @@ public class MockOrganization implements Organization { private final HashMap<IssueId, WrappedIssue> issues; private final HashMap<PropertyId, PropertyInfo> properties; + @Inject + @SuppressWarnings("unused") + public MockOrganization() { + this(Clock.systemUTC()); + } + public MockOrganization(Clock clock) { this.clock = clock; @@ -82,17 +89,17 @@ public class MockOrganization implements Organization { @Override public URI issueCreationUri(PropertyId propertyId) { - return null; + return URI.create("www.issues.com/" + propertyId.id()); } @Override public URI contactsUri(PropertyId propertyId) { - return null; + return URI.create("www.contacts.com/" + propertyId.id()); } @Override public URI propertyUri(PropertyId propertyId) { - return null; + return URI.create("www.properties.com/" + propertyId.id()); } public void close(IssueId issueId) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/api/Tenant.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/api/Tenant.java index 4889f789819..9b8643c7167 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/api/Tenant.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/api/Tenant.java @@ -29,24 +29,25 @@ public class Tenant { public Tenant(TenantId id, Optional<UserGroup> userGroup, Optional<Property> property, Optional<AthenzDomain> athenzDomain, Optional<PropertyId> propertyId) { if (id.isUser()) { - require(!userGroup.isPresent(), "User tenant '%s' cannot have a user group.", id); - require(!property.isPresent(), "User tenant '%s' cannot have a property.", id); - require(!propertyId.isPresent(), "User tenant '%s' cannot have a property ID.", id); - require(!athenzDomain.isPresent(), "User tenant '%s' cannot have an athens domain.", id); + require( ! userGroup.isPresent(), "User tenant '%s' cannot have a user group.", id); + require( ! property.isPresent(), "User tenant '%s' cannot have a property.", id); + require( ! propertyId.isPresent(), "User tenant '%s' cannot have a property ID.", id); + require( ! athenzDomain.isPresent(), "User tenant '%s' cannot have an athens domain.", id); } else if (athenzDomain.isPresent()) { - require(property.isPresent(), "Athens tenant '%s' must have a property.", id); - require(!userGroup.isPresent(), "Athens tenant '%s' cannot have a user group.", id); - require(athenzDomain.isPresent(), "Athens tenant '%s' must have an athens domain.", id); + require( property.isPresent(), "Athens tenant '%s' must have a property.", id); + require( ! userGroup.isPresent(), "Athens tenant '%s' cannot have a user group.", id); + require( athenzDomain.isPresent(), "Athens tenant '%s' must have an athens domain.", id); } else { - require(property.isPresent(), "OpsDB tenant '%s' must have a property.", id); - require(userGroup.isPresent(), "OpsDb tenant '%s' must have a user group.", id); - require(!athenzDomain.isPresent(), "OpsDb tenant '%s' cannot have an athens domain.", id); + require( property.isPresent(), "OpsDB tenant '%s' must have a property.", id); + require( userGroup.isPresent(), "OpsDb tenant '%s' must have a user group.", id); + require( ! athenzDomain.isPresent(), "OpsDb tenant '%s' cannot have an athens domain.", id); } this.id = id; this.userGroup = userGroup; this.property = property; this.athenzDomain = athenzDomain; this.propertyId = propertyId; // TODO: Check validity after TODO@14. OpsDb tenants have this set in Sherpa, while athens tenants do not. + // TODO: Require PropertyId for non-users, and fetch Property from EntityService (which will be moved to Organization) in the controller. } public boolean isAthensTenant() { return athenzDomain.isPresent(); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index c50f1464be7..30444f8bc93 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -53,6 +53,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.UserId; import com.yahoo.vespa.hosted.controller.api.integration.MetricsService; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; import com.yahoo.vespa.hosted.controller.api.integration.configserver.Log; +import com.yahoo.vespa.hosted.controller.api.integration.organization.User; import com.yahoo.vespa.hosted.controller.api.integration.routing.RotationStatus; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.ApplicationRevision; @@ -164,6 +165,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (path.matches("/application/v4/property")) return properties(); if (path.matches("/application/v4/cookiefreshness")) return cookieFreshness(request); if (path.matches("/application/v4/tenant/{tenant}")) return tenant(path.get("tenant"), request); + if (path.matches("/application/v4/tenant/{tenant}/property")) return property(path.get("tenant")); if (path.matches("/application/v4/tenant/{tenant}/application")) return applications(path.get("tenant"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), path, request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deployment(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); @@ -305,6 +307,20 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return ErrorResponse.notFoundError("Tenant '" + tenantName + "' does not exist"); return new SlimeJsonResponse(toSlime(tenant.get(), request, true)); } + + private HttpResponse property(String tenantName) { + Optional<Tenant> tenant = controller.tenants().tenant(new TenantId(tenantName)); + if ( ! tenant.isPresent()) + return ErrorResponse.notFoundError("Tenant '" + tenantName + "' does not exist"); + if ( ! tenant.get().getPropertyId().isPresent()) + return ErrorResponse.notFoundError("Tenant '" + tenantName + "' does not have the required property id"); + + PropertyId propertyId = tenant.get().getPropertyId().get(); + return new SlimeJsonResponse(toSlime(controller.organization().propertyUri(propertyId), + controller.organization().contactsUri(propertyId), + controller.organization().issueCreationUri(propertyId), + controller.organization().contactsFor(propertyId))); + } private HttpResponse applications(String tenantName, HttpRequest request) { TenantName tenant = TenantName.from(tenantName); @@ -990,6 +1006,21 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return slime; } + private Slime toSlime(URI propertyUri, URI contactsUri, URI issueCreationUri, List<? extends List<? extends User>> contacts) { + Slime slime = new Slime(); + Cursor root = slime.setObject(); + root.setString("propertyUri", propertyUri.toString()); + root.setString("contactsUri", contactsUri.toString()); + root.setString("issueCreationUri", issueCreationUri.toString()); + Cursor lists = root.setArray("contacts"); + for (List<? extends User> contactList : contacts) { + Cursor list = lists.addArray(); + for (User contact : contactList) + list.addString(contact.toString()); + } + return slime; + } + private void toSlime(Application application, Cursor object, HttpRequest request) { object.setString("application", application.id().application().value()); object.setString("instance", application.id().instance().value()); 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 1ac5dfeb58a..13c6306a88e 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 @@ -9,8 +9,11 @@ import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.ConfigServerClientMock; import com.yahoo.vespa.hosted.controller.api.identifiers.AthenzDomain; +import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId; import com.yahoo.vespa.hosted.controller.api.identifiers.UserId; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; +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.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.ClusterInfo; import com.yahoo.vespa.hosted.controller.application.ClusterUtilization; @@ -37,6 +40,8 @@ import java.io.UncheckedIOException; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,7 +84,7 @@ public class ApplicationApiTest extends ControllerContainerTest { new File("cookiefreshness.json")); // POST (add) a tenant without property ID tester.assertResponse(request("/application/v4/tenant/tenant1", - "{\"athensDomain\":\"domain1\", \"property\":\"property1\"}", + "{\"athensDomain\":\"domain1\", \"property\":\"property1\"}", Request.Method.POST), new File("tenant-without-applications.json")); // PUT (modify) a tenant @@ -101,6 +106,7 @@ public class ApplicationApiTest extends ControllerContainerTest { // GET a tenant tester.assertResponse(request("/application/v4/tenant/tenant1", "", Request.Method.GET), new File("tenant-with-application.json")); + // GET tenant applications tester.assertResponse(request("/application/v4/tenant/tenant1/application/", "", Request.Method.GET), new File("application-list.json")); @@ -250,6 +256,11 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/tenant/tenant2", "", Request.Method.GET), new File("tenant-without-applications-with-id.json")); + // GET property info for a tenant with property ID + addPropertyData((MockOrganization) controllerTester.controller().organization(), "1234"); + tester.assertResponse(request("/application/v4/tenant/tenant2/property", "", Request.Method.GET), + new File("property-info.json")); + // Test legacy OpsDB tenants // POST (add) an OpsDB tenant with property ID tester.assertResponse(request("/application/v4/tenant/tenant3", @@ -286,6 +297,13 @@ public class ApplicationApiTest extends ControllerContainerTest { controllerTester.controller().deconstruct(); } + private void addPropertyData(MockOrganization organization, String propertyIdValue) { + PropertyId propertyId = new PropertyId(propertyIdValue); + organization.addProperty(propertyId); + organization.setContactsFor(propertyId, Arrays.asList(Collections.singletonList(User.from("alice")), + Collections.singletonList(User.from("bob")))); + } + @Test public void testDeployDirectly() throws Exception { // Setup @@ -755,4 +773,5 @@ public class ApplicationApiTest extends ControllerContainerTest { } } } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-list.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-list.json index a9d9cd33ae8..d7ec9a738f2 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-list.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-list.json @@ -8,4 +8,4 @@ }, "url": "http://localhost:8080/application/v4/tenant/tenant1" } -]
\ No newline at end of file +] |