summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorolaaun <ola.aunroe@gmail.com>2018-10-16 12:32:51 +0200
committerGitHub <noreply@github.com>2018-10-16 12:32:51 +0200
commit13c06dda80a8229991ddab2b8579baefb5f08f65 (patch)
tree377f8f82f6ecff7e8bad55ffa3645bec90cd85a5 /controller-server
parent2cc64e617ff11f763d9fa165b37d19df0ced4114 (diff)
Revert 7315 revert 7274 olaaun/contact info maintainer feed to api (#7320)
* Revert "Revert "ContactInformationMaintainer now feeds to ContactInfoAPI instead of d… (#7274)" (#7315)" This reverts commit 0a9e36c185cf555dd851b065c16ef720665dd906. * Changed authorities config from string to list. Shortened namespace.
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainer.java121
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/contactinfo/ContactInfoHandler.java8
-rw-r--r--controller-server/src/main/resources/configdefinitions/api-authority.def4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ContactInformationMaintainerTest.java37
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java7
7 files changed, 145 insertions, 43 deletions
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..3cf3c47a6f3 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,17 +1,31 @@
// 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.authority.config.ApiAuthorityConfig;
import com.yahoo.config.provision.SystemName;
import com.yahoo.log.LogLevel;
+import com.yahoo.slime.ArrayTraverser;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.config.SlimeUtils;
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.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 org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import java.io.IOException;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
@@ -29,44 +43,107 @@ public class ContactInformationMaintainer extends Maintainer {
private static final Logger log = Logger.getLogger(ContactInformationMaintainer.class.getName());
private final Organization organization;
+ private final List<String> baseUris;
+ private CloseableHttpClient httpClient = HttpClientBuilder.create().build();
- public ContactInformationMaintainer(Controller controller, Duration interval, JobControl jobControl, Organization organization) {
+ public ContactInformationMaintainer(Controller controller, Duration interval, JobControl jobControl, Organization organization, ApiAuthorityConfig apiAuthorityConfig) {
super(controller, interval, jobControl, null, EnumSet.of(SystemName.cd, SystemName.main));
this.organization = Objects.requireNonNull(organization, "organization must be non-null");
+ this.baseUris = apiAuthorityConfig.authorities();
}
+ // The maintainer will eventually feed contact info to systems other than its own, determined by the baseUris list.
@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 (String baseUri : baseUris) {
+ for (String tenantName : getTenantList(baseUri)) {
+ Optional<PropertyId> tenantPropertyId = getPropertyId(tenantName, baseUri);
+ if (!tenantPropertyId.isPresent())
+ continue;
+ findContact(tenantPropertyId.get()).ifPresent(contact -> {
+ feedContact(tenantName, contact, baseUri);
});
- } catch (Exception e) {
- log.log(LogLevel.WARNING, "Failed to update contact information for " + tenant + ": " +
- Exceptions.toMessageString(e) + ". Retrying in " +
- maintenanceInterval());
}
}
}
- /** Find contact information for given tenant */
- private Optional<Contact> findContact(AthenzTenant tenant) {
- if (!tenant.propertyId().isPresent()) {
- return Optional.empty();
+ private void feedContact(String tenantName, Contact contact, String baseUri) {
+ try {
+ CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+ String uri = baseUri + "contactinfo/v1/tenant/" + tenantName;
+ HttpPost httpPost = new HttpPost(uri);
+ httpPost.setEntity(contactToByteArrayEntity(contact));
+ httpClient.execute(httpPost);
+ } catch (Exception e) {
+ log.log(LogLevel.WARNING, "Failed to update contact information for " + tenantName + ": " +
+ Exceptions.toMessageString(e) + ". Retrying in " +
+ maintenanceInterval());
+ }
+ }
+
+ private ByteArrayEntity contactToByteArrayEntity(Contact contact) throws IOException {
+ Slime slime = new Slime();
+ Cursor cursor = slime.setObject();
+ cursor.setString("url", contact.url().toString());
+ cursor.setString("issueTrackerUrl", contact.issueTrackerUrl().toString());
+ cursor.setString("propertyUrl", contact.propertyUrl().toString());
+ Cursor personsCursor = cursor.setArray("persons");
+ for (List<String> personList : contact.persons()) {
+ Cursor sublist = personsCursor.addArray();
+ for(String person : personList) {
+ sublist.addString(person);
+ }
+ }
+ return new ByteArrayEntity(SlimeUtils.toJsonBytes(slime));
+ }
+
+ private List<String> getTenantList(String baseUri) {
+ List<String> tenantList = new ArrayList<>();
+ HttpGet getRequest = new HttpGet(baseUri + "application/v4/tenant/");
+ try {
+ HttpResponse response = httpClient.execute(getRequest);
+ Slime slime = SlimeUtils.jsonToSlime(EntityUtils.toByteArray(response.getEntity()));
+ Inspector inspector = slime.get();
+ inspector.traverse((ArrayTraverser) (index, tenant) -> {
+ tenantList.add(tenant.field("tenant").asString());
+ });
+ } catch (IOException e) {
+ log.log(LogLevel.WARNING, "Failed to get tenant list from base URI: " + baseUri.toString() +
+ Exceptions.toMessageString(e) + ". Retrying in " +
+ maintenanceInterval());
}
- List<List<String>> persons = organization.contactsFor(tenant.propertyId().get())
+ return tenantList;
+ }
+
+ private Optional<PropertyId> getPropertyId(String tenantName, String baseUri) {
+ Optional<PropertyId> propertyId = Optional.empty();
+ HttpGet getRequest = new HttpGet(baseUri + "application/v4/tenant/" + tenantName);
+ try {
+ HttpResponse response = httpClient.execute(getRequest);
+ Slime slime = SlimeUtils.jsonToSlime(EntityUtils.toByteArray(response.getEntity()));
+ Inspector inspector = slime.get();
+ if (!inspector.field("propertyId").valid()) {
+ log.log(LogLevel.WARNING, "Unable to get property id for " + tenantName);
+ return Optional.empty();
+ }
+ propertyId = Optional.of(new PropertyId(inspector.field("propertyId").asString()));
+ } catch (IOException e) {
+ log.log(LogLevel.WARNING, "Unable to get property idfor " + tenantName, e);
+ }
+ return propertyId;
+ }
+
+ /** Find contact information for given tenant */
+ private Optional<Contact> findContact(PropertyId propertyId) {
+ List<List<String>> persons = organization.contactsFor(propertyId)
.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()),
+ return Optional.of(new Contact(organization.contactsUri(propertyId),
+ organization.propertyUri(propertyId),
+ organization.issueCreationUri(propertyId),
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 c67eab8826e..33555c08a43 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,6 +4,7 @@ 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.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;
@@ -49,7 +50,7 @@ public class ControllerMaintenance extends AbstractComponent {
private final ContactInformationMaintainer contactInformationMaintainer;
@SuppressWarnings("unused") // instantiated by Dependency Injection
- public ControllerMaintenance(MaintainerConfig maintainerConfig, Controller controller, CuratorDb curator,
+ public ControllerMaintenance(MaintainerConfig maintainerConfig, ApiAuthorityConfig apiAuthorityConfig, Controller controller, CuratorDb curator,
JobControl jobControl, Metric metric, Chef chefClient,
DeploymentIssues deploymentIssues, OwnershipIssues ownershipIssues,
NameService nameService, NodeRepositoryClientInterface nodeRepositoryClient,
@@ -72,7 +73,7 @@ public class ControllerMaintenance extends AbstractComponent {
jobRunner = new JobRunner(controller, Duration.ofSeconds(30), 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, organization, apiAuthorityConfig);
}
public Upgrader upgrader() { return upgrader; }
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 5c4573e1ce7..7651381b810 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
@@ -13,9 +13,6 @@ import com.yahoo.slime.Inspector;
import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.SlimeUtils;
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.Organization;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.User;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponse;
import com.yahoo.vespa.hosted.controller.restapi.SlimeJsonResponse;
import com.yahoo.vespa.hosted.controller.restapi.StringResponse;
@@ -24,16 +21,11 @@ import com.yahoo.vespa.hosted.controller.tenant.Contact;
import com.yahoo.yolean.Exceptions;
import java.io.IOException;
-import java.io.ObjectInputStream;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
-import java.util.stream.Collectors;
/**
* This implements the contactinfo/v1 API which allows getting and feeding
diff --git a/controller-server/src/main/resources/configdefinitions/api-authority.def b/controller-server/src/main/resources/configdefinitions/api-authority.def
new file mode 100644
index 00000000000..9ab652ecc81
--- /dev/null
+++ b/controller-server/src/main/resources/configdefinitions/api-authority.def
@@ -0,0 +1,4 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=vespa.hosted.controller.authority.config
+
+authorities[] string \ No newline at end of file
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..a46215eaf22 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
@@ -1,13 +1,17 @@
// 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.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.github.tomakehurst.wiremock.verification.LoggedRequest;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.authority.config.ApiAuthorityConfig;
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 org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import java.net.URI;
@@ -18,9 +22,16 @@ import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.findAll;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
/**
* @author mpolden
@@ -29,13 +40,27 @@ public class ContactInformationMaintainerTest {
private ControllerTester tester;
private ContactInformationMaintainer maintainer;
+ private String contactInfoPath = "/contactinfo/v1/tenant/tenant1";
+ private String tenantPath = "/application/v4/tenant/";
+
+ @Rule
+ public WireMockRule wireMockRule = new WireMockRule(4443);
+
@Before
public void before() {
tester = new ControllerTester();
+ ApiAuthorityConfig.Builder apiAuthorityConfigBuilder = new ApiAuthorityConfig.Builder().authorities("http://localhost:4443/");
+ ApiAuthorityConfig apiAuthorityConfig = new ApiAuthorityConfig(apiAuthorityConfigBuilder);
maintainer = new ContactInformationMaintainer(tester.controller(), Duration.ofDays(1),
new JobControl(tester.controller().curator()),
- tester.organization());
+ tester.organization(), apiAuthorityConfig);
+ wireMockRule.stubFor(post(urlEqualTo(contactInfoPath))
+ .willReturn(aResponse().withStatus(200)));
+ wireMockRule.stubFor(get(urlEqualTo(tenantPath))
+ .willReturn(okJson("[{\"tenant\":\"tenant1\"}]")));
+ wireMockRule.stubFor(get(urlEqualTo(tenantPath + "tenant1"))
+ .willReturn(okJson("{\"tenant\":\"tenant1\", \"athensDomain\":\"domain\", \"property\":\"property\", \"propertyId\":\"1\"}")));
}
@Test
@@ -44,13 +69,13 @@ public class ContactInformationMaintainerTest {
TenantName name = tester.createTenant("tenant1", "domain1", propertyId);
Supplier<AthenzTenant> tenant = () -> tester.controller().tenants().requireAthenzTenant(name);
assertFalse("No contact information initially", tenant.get().contact().isPresent());
-
Contact contact = testContact();
registerContact(propertyId, contact);
maintainer.run();
-
- assertTrue("Contact information added", tenant.get().contact().isPresent());
- assertEquals(contact, tenant.get().contact().get());
+ verify(1, postRequestedFor(urlEqualTo(contactInfoPath)));
+ LoggedRequest request = findAll(postRequestedFor(urlEqualTo(contactInfoPath))).get(0);
+ String expectedBody = "{\"url\":\"http://contact1.test\",\"issueTrackerUrl\":\"http://issue-tracker1.test\",\"propertyUrl\":\"http://property1.test\",\"persons\":[[\"alice\"],[\"bob\"]]}";
+ assertEquals(expectedBody, new String(request.getBody()));
}
private void registerContact(long propertyId, Contact contact) {
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 9574256c065..e47cdf887f9 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
@@ -80,7 +80,11 @@ public class ControllerContainerTest {
" <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.ConfigServerProxyMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.MetricsServiceMock'/>\n" +
- " <component id='com.yahoo.vespa.hosted.controller.maintenance.ControllerMaintenance'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.controller.maintenance.ControllerMaintenance'>\n" +
+ " <config name=\"vespa.hosted.controller.authority.config.api-authority\">\n" +
+ " <authorities><item>https://localhost:4443/</item></authorities>\n" +
+ " </config>" +
+ " </component>" +
" <component id='com.yahoo.vespa.hosted.controller.maintenance.JobControl'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.RoutingGeneratorMock'/>\n" +
" <component id='com.yahoo.vespa.hosted.controller.integration.ArtifactRepositoryMock'/>\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 f2e105f2c31..d620d78d3f0 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
@@ -47,13 +47,13 @@ import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.BuildJob;
import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock;
import com.yahoo.vespa.hosted.controller.integration.MetricsServiceMock;
-import com.yahoo.vespa.hosted.controller.maintenance.ContactInformationMaintainer;
import com.yahoo.vespa.hosted.controller.maintenance.DeploymentMetricsMaintainer;
import com.yahoo.vespa.hosted.controller.maintenance.JobControl;
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 org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -1269,9 +1269,8 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
private void updateContactInformation() {
- new ContactInformationMaintainer(tester.controller(), Duration.ofDays(1),
- new JobControl(tester.controller().curator()),
- organization()).run();
+ 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")));
+ tester.controller().tenants().lockIfPresent(TenantName.from("tenant2"), lockedTenant -> tester.controller().tenants().store(lockedTenant.with(contact)));
}
private void registerContact(long propertyId) {