aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2018-09-21 05:46:52 -0700
committerGitHub <noreply@github.com>2018-09-21 05:46:52 -0700
commit05a6548077b3b27e3e8f0ea004cc29b7e29c48ea (patch)
treebf464b8a0cd026f8c0c94010e22f65c0e5df6155
parent218f9c117793b91ec130aa1fd1bfd7410b2336e0 (diff)
parentf64c07dff75caa6d9d03c60dd2b51a8c27db247d (diff)
Merge pull request #7046 from vespa-engine/jvenstad/confirmation-issues-after-90-days
Record time of creation of new applications
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java38
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java34
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java4
7 files changed, 63 insertions, 41 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java
index 5b77330eff4..a6c3f11470d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Application.java
@@ -41,6 +41,7 @@ import java.util.stream.Collectors;
public class Application {
private final ApplicationId id;
+ private final Instant createdAt;
private final DeploymentSpec deploymentSpec;
private final ValidationOverrides validationOverrides;
private final Map<ZoneId, Deployment> deployments;
@@ -53,28 +54,29 @@ public class Application {
private final Map<HostName, RotationStatus> rotationStatus;
/** Creates an empty application */
- public Application(ApplicationId id) {
- this(id, DeploymentSpec.empty, ValidationOverrides.empty, Collections.emptyMap(),
+ public Application(ApplicationId id, Instant now) {
+ this(id, now, DeploymentSpec.empty, ValidationOverrides.empty, Collections.emptyMap(),
new DeploymentJobs(OptionalLong.empty(), Collections.emptyList(), Optional.empty(), false),
Change.empty(), Change.empty(), Optional.empty(), new ApplicationMetrics(0, 0),
Optional.empty(), Collections.emptyMap());
}
/** Used from persistence layer: Do not use */
- public Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
+ public Application(ApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
List<Deployment> deployments, DeploymentJobs deploymentJobs, Change change,
Change outstandingChange, Optional<IssueId> ownershipIssueId, ApplicationMetrics metrics,
Optional<RotationId> rotation, Map<HostName, RotationStatus> rotationStatus) {
- this(id, deploymentSpec, validationOverrides,
+ this(id, createdAt, deploymentSpec, validationOverrides,
deployments.stream().collect(Collectors.toMap(Deployment::zone, d -> d)),
deploymentJobs, change, outstandingChange, ownershipIssueId, metrics, rotation, rotationStatus);
}
- Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
+ Application(ApplicationId id, Instant createdAt, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Change change,
Change outstandingChange, Optional<IssueId> ownershipIssueId, ApplicationMetrics metrics,
Optional<RotationId> rotation, Map<HostName, RotationStatus> rotationStatus) {
this.id = Objects.requireNonNull(id, "id cannot be null");
+ this.createdAt = Objects.requireNonNull(createdAt, "instant of creation cannot be null");
this.deploymentSpec = Objects.requireNonNull(deploymentSpec, "deploymentSpec cannot be null");
this.validationOverrides = Objects.requireNonNull(validationOverrides, "validationOverrides cannot be null");
this.deployments = ImmutableMap.copyOf(Objects.requireNonNull(deployments, "deployments cannot be null"));
@@ -89,6 +91,8 @@ public class Application {
public ApplicationId id() { return id; }
+ public Instant createdAt() { return createdAt; }
+
/**
* Returns the last deployed deployment spec of this application,
* or the empty deployment spec if it has never been deployed
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index af5b9198343..955faeb3e51 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -274,7 +274,7 @@ public class ApplicationController {
zmsClient.addApplication(((AthenzTenant) tenant.get()).domain(),
new com.yahoo.vespa.hosted.controller.api.identifiers.ApplicationId(id.application().value()));
}
- LockedApplication application = new LockedApplication(new Application(id), lock);
+ LockedApplication application = new LockedApplication(new Application(id, clock.instant()), lock);
store(application);
log.info("Created " + application);
return application.get();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
index e8d50d72669..433a6d3ed38 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/LockedApplication.java
@@ -42,6 +42,7 @@ public class LockedApplication {
private final Lock lock;
private final ApplicationId id;
+ private final Instant createdAt;
private final DeploymentSpec deploymentSpec;
private final ValidationOverrides validationOverrides;
private final Map<ZoneId, Deployment> deployments;
@@ -60,7 +61,7 @@ public class LockedApplication {
* @param lock The lock for the application.
*/
LockedApplication(Application application, Lock lock) {
- this(Objects.requireNonNull(lock, "lock cannot be null"), application.id(),
+ this(Objects.requireNonNull(lock, "lock cannot be null"), application.id(), application.createdAt(),
application.deploymentSpec(), application.validationOverrides(),
application.deployments(),
application.deploymentJobs(), application.change(), application.outstandingChange(),
@@ -69,13 +70,14 @@ public class LockedApplication {
application.rotationStatus());
}
- private LockedApplication(Lock lock, ApplicationId id,
+ private LockedApplication(Lock lock, ApplicationId id, Instant createdAt,
DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides,
Map<ZoneId, Deployment> deployments, DeploymentJobs deploymentJobs, Change change,
Change outstandingChange, Optional<IssueId> ownershipIssueId, ApplicationMetrics metrics,
Optional<RotationId> rotation, Map<HostName, RotationStatus> rotationStatus) {
this.lock = lock;
this.id = id;
+ this.createdAt = createdAt;
this.deploymentSpec = deploymentSpec;
this.validationOverrides = validationOverrides;
this.deployments = deployments;
@@ -90,37 +92,37 @@ public class LockedApplication {
/** Returns a read-only copy of this */
public Application get() {
- return new Application(id, deploymentSpec, validationOverrides, deployments, deploymentJobs, change,
+ return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change,
outstandingChange, ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withBuiltInternally(boolean builtInternally) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.withBuiltInternally(builtInternally), change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withProjectId(OptionalLong projectId) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.withProjectId(projectId), change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withDeploymentIssueId(IssueId issueId) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.with(issueId), change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withJobCompletion(long projectId, JobType jobType, JobStatus.JobRun completion,
Optional<DeploymentJobs.JobError> jobError) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.withCompletion(projectId, jobType, completion, jobError),
change, outstandingChange, ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withJobTriggering(JobType jobType, JobStatus.JobRun job) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.withTriggering(jobType, job), change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
@@ -170,55 +172,55 @@ public class LockedApplication {
}
public LockedApplication withoutDeploymentJob(JobType jobType) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs.without(jobType), change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication with(DeploymentSpec deploymentSpec) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication with(ValidationOverrides validationOverrides) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withChange(Change change) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withOutstandingChange(Change outstandingChange) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication withOwnershipIssueId(IssueId issueId) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
Optional.ofNullable(issueId), metrics, rotation, rotationStatus);
}
public LockedApplication with(MetricsService.ApplicationMetrics metrics) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
public LockedApplication with(RotationId rotation) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, Optional.of(rotation), rotationStatus);
}
public LockedApplication withRotationStatus(Map<HostName, RotationStatus> rotationStatus) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments, deploymentJobs, change,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, change,
outstandingChange, ownershipIssueId, metrics, rotation, rotationStatus);
}
@@ -230,7 +232,7 @@ public class LockedApplication {
}
private LockedApplication with(Map<ZoneId, Deployment> deployments) {
- return new LockedApplication(lock, id, deploymentSpec, validationOverrides, deployments,
+ return new LockedApplication(lock, id, createdAt, deploymentSpec, validationOverrides, deployments,
deploymentJobs, change, outstandingChange,
ownershipIssueId, metrics, rotation, rotationStatus);
}
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 b12c7a676e1..93578e97cc4 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
@@ -49,22 +49,24 @@ public class ApplicationOwnershipConfirmer extends Maintainer {
/** File an ownership issue with the owners of all applications we know about. */
private void confirmApplicationOwnerships() {
ApplicationList.from(controller().applications().asList())
- .notPullRequest()
- .hasProductionDeployment()
- .asList()
- .forEach(application -> {
- 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.ifPresent(issueId -> store(issueId, application.id()));
- }
- catch (RuntimeException e) { // Catch errors due to wrong data in the controller, or issues client timeout.
- log.log(Level.WARNING, "Exception caught when attempting to file an issue for " + application.id(), e);
- }
- });
+ .notPullRequest()
+ .hasProductionDeployment()
+ .asList()
+ .stream()
+ .filter(application -> application.createdAt().isBefore(controller().clock().instant().minus(Duration.ofDays(90))))
+ .forEach(application -> {
+ 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.ifPresent(issueId -> store(issueId, application.id()));
+ }
+ catch (RuntimeException e) { // Catch errors due to wrong data in the controller, or issues client timeout.
+ log.log(Level.WARNING, "Exception caught when attempting to file an issue for " + application.id(), e);
+ }
+ });
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
index 9ee23dbe51b..3975613835b 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializer.java
@@ -53,6 +53,7 @@ public class ApplicationSerializer {
// Application fields
private final String idField = "id";
+ private final String createdAtField = "createdAt";
private final String deploymentSpecField = "deploymentSpecField";
private final String validationOverridesField = "validationOverrides";
private final String deploymentsField = "deployments";
@@ -135,6 +136,7 @@ public class ApplicationSerializer {
Slime slime = new Slime();
Cursor root = slime.setObject();
root.setString(idField, application.id().serializedForm());
+ root.setLong(createdAtField, application.createdAt().toEpochMilli());
root.setString(deploymentSpecField, application.deploymentSpec().xmlForm());
root.setString(validationOverridesField, application.validationOverrides().xmlForm());
deploymentsToSlime(application.deployments().values(), root.setArray(deploymentsField));
@@ -287,6 +289,7 @@ public class ApplicationSerializer {
Inspector root = slime.get();
ApplicationId id = ApplicationId.fromSerializedForm(root.field(idField).asString());
+ Instant createdAt = Instant.ofEpochMilli(root.field(createdAtField).asLong());
DeploymentSpec deploymentSpec = DeploymentSpec.fromXml(root.field(deploymentSpecField).asString(), false);
ValidationOverrides validationOverrides = ValidationOverrides.fromXml(root.field(validationOverridesField).asString());
List<Deployment> deployments = deploymentsFromSlime(root.field(deploymentsField));
@@ -299,7 +302,7 @@ public class ApplicationSerializer {
Optional<RotationId> rotation = rotationFromSlime(root.field(rotationField));
Map<HostName, RotationStatus> rotationStatus = rotationStatusFromSlime(root.field(rotationStatusField));
- return new Application(id, deploymentSpec, validationOverrides, deployments, deploymentJobs, deploying,
+ return new Application(id, createdAt, deploymentSpec, validationOverrides, deployments, deploymentJobs, deploying,
outstandingChange, ownershipIssueId, metrics, rotation, rotationStatus);
}
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 555fdb338e8..2694e205a68 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
@@ -59,6 +59,13 @@ public class ApplicationOwnershipConfirmerTest {
confirmer.maintain();
confirmer.maintain();
+ assertFalse("No issue is stored for an application newer than 3 months.", propertyApp.get().ownershipIssueId().isPresent());
+ assertFalse("No issue is stored for an application newer than 3 months.", userApp.get().ownershipIssueId().isPresent());
+
+ tester.clock().advance(Duration.ofDays(91));
+ confirmer.maintain();
+ confirmer.maintain();
+
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);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
index 8d99dfc5c16..3e09c9078a0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
@@ -32,6 +32,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -97,6 +99,7 @@ public class ApplicationSerializerTest {
rotationStatus.put(HostName.from("rot2.fqdn"), RotationStatus.out);
Application original = new Application(ApplicationId.from("t1", "a1", "i1"),
+ Instant.now().truncatedTo(ChronoUnit.MILLIS),
deploymentSpec,
validationOverrides,
deployments, deploymentJobs,
@@ -110,6 +113,7 @@ public class ApplicationSerializerTest {
Application serialized = applicationSerializer.fromSlime(applicationSerializer.toSlime(original));
assertEquals(original.id(), serialized.id());
+ assertEquals(original.createdAt(), serialized.createdAt());
assertEquals(original.deploymentSpec().xmlForm(), serialized.deploymentSpec().xmlForm());
assertEquals(original.validationOverrides().xmlForm(), serialized.validationOverrides().xmlForm());