diff options
Diffstat (limited to 'controller-server')
11 files changed, 248 insertions, 29 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 d26ff8ad65d..3fafd81d10e 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 @@ -8,6 +8,7 @@ import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; @@ -20,7 +21,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import java.util.stream.Collector; import java.util.stream.Collectors; /** @@ -39,26 +39,27 @@ public class Application { private final DeploymentJobs deploymentJobs; private final Optional<Change> deploying; private final boolean outstandingChange; + private final Optional<IssueId> ownershipIssueId; /** Creates an empty application */ public Application(ApplicationId id) { this(id, DeploymentSpec.empty, ValidationOverrides.empty, ImmutableMap.of(), new DeploymentJobs(Optional.empty(), Collections.emptyList(), Optional.empty()), - Optional.empty(), false); + Optional.empty(), false, Optional.empty()); } /** Used from persistence layer: Do not use */ public Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides, - List<Deployment> deployments, - DeploymentJobs deploymentJobs, Optional<Change> deploying, boolean outstandingChange) { + List<Deployment> deployments, DeploymentJobs deploymentJobs, Optional<Change> deploying, + boolean outstandingChange, Optional<IssueId> ownershipIssueId) { this(id, deploymentSpec, validationOverrides, deployments.stream().collect(Collectors.toMap(Deployment::zone, d -> d)), - deploymentJobs, deploying, outstandingChange); + deploymentJobs, deploying, outstandingChange, ownershipIssueId); } Application(ApplicationId id, DeploymentSpec deploymentSpec, ValidationOverrides validationOverrides, Map<Zone, Deployment> deployments, DeploymentJobs deploymentJobs, Optional<Change> deploying, - boolean outstandingChange) { + boolean outstandingChange, Optional<IssueId> ownershipIssueId) { Objects.requireNonNull(id, "id cannot be null"); Objects.requireNonNull(deploymentSpec, "deploymentSpec cannot be null"); Objects.requireNonNull(validationOverrides, "validationOverrides cannot be null"); @@ -72,6 +73,7 @@ public class Application { this.deploymentJobs = deploymentJobs; this.deploying = deploying; this.outstandingChange = outstandingChange; + this.ownershipIssueId = ownershipIssueId; } public ApplicationId id() { return id; } @@ -181,5 +183,9 @@ public class Application { public boolean isBlocked(Instant instant) { return ! deploymentSpec.canUpgradeAt(instant) || ! deploymentSpec.canChangeRevisionAt(instant); } - + + public Optional<IssueId> ownershipIssueId() { + return ownershipIssueId; + } + } 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 56b76260f14..f34583d3998 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 @@ -36,20 +36,20 @@ public class LockedApplication extends Application { LockedApplication(Application application, Lock lock) { super(application.id(), application.deploymentSpec(), application.validationOverrides(), application.deployments(), application.deploymentJobs(), application.deploying(), - application.hasOutstandingChange()); + application.hasOutstandingChange(), application.ownershipIssueId()); this.lock = Objects.requireNonNull(lock, "lock cannot be null"); } public LockedApplication withProjectId(long projectId) { return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments(), deploymentJobs().withProjectId(projectId), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication with(IssueId issueId) { return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments(), deploymentJobs().with(issueId), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withJobCompletion(DeploymentJobs.JobReport report, Instant notificationTime, @@ -58,7 +58,7 @@ public class LockedApplication extends Application { deployments(), deploymentJobs().withCompletion(report, notificationTime, controller), - deploying(), hasOutstandingChange()), lock); + deploying(), hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withJobTriggering(DeploymentJobs.JobType type, Optional<Change> change, @@ -70,7 +70,7 @@ public class LockedApplication extends Application { determineTriggerRevision(type, controller), reason, triggerTime), - deploying(), hasOutstandingChange()), lock); + deploying(), hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication with(Deployment deployment) { @@ -78,13 +78,13 @@ public class LockedApplication extends Application { deployments.put(deployment.zone(), deployment); return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments, deploymentJobs(), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication with(DeploymentJobs deploymentJobs) { return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments(), deploymentJobs, deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withoutDeploymentIn(Zone zone) { @@ -92,38 +92,44 @@ public class LockedApplication extends Application { deployments.remove(zone); return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments, deploymentJobs(), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withoutDeploymentJob(DeploymentJobs.JobType jobType) { DeploymentJobs deploymentJobs = deploymentJobs().without(jobType); return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments(), deploymentJobs, deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication with(DeploymentSpec deploymentSpec) { return new LockedApplication(new Application(id(), deploymentSpec, validationOverrides(), deployments(), deploymentJobs(), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication with(ValidationOverrides validationOverrides) { return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides, deployments(), deploymentJobs(), deploying(), - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withDeploying(Optional<Change> deploying) { return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), deployments(), deploymentJobs(), deploying, - hasOutstandingChange()), lock); + hasOutstandingChange(), ownershipIssueId()), lock); } public LockedApplication withOutstandingChange(boolean outstandingChange) { - return new LockedApplication(new Application(id(), deploymentSpec(), - validationOverrides(), deployments(), - deploymentJobs(), deploying(), outstandingChange), lock); + return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), + deployments(), deploymentJobs(), deploying(), + outstandingChange, ownershipIssueId()), lock); + } + + public LockedApplication withOwnershipIssueId(IssueId issueId) { + return new LockedApplication(new Application(id(), deploymentSpec(), validationOverrides(), + deployments(), deploymentJobs(), deploying(), + hasOutstandingChange(), Optional.of(issueId)), lock); } private Version determineTriggerVersion(DeploymentJobs.JobType jobType, Controller controller) { 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 new file mode 100644 index 00000000000..5d9cf291af7 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmer.java @@ -0,0 +1,85 @@ +package com.yahoo.vespa.hosted.controller.maintenance; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.vespa.curator.Lock; +import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.api.Tenant; +import com.yahoo.vespa.hosted.controller.api.application.v4.model.TenantType; +import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId; +import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId; +import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipIssues; +import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; +import com.yahoo.vespa.hosted.controller.api.integration.organization.User; + +import java.time.Duration; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.logging.Level; + +public class ApplicationOwnershipConfirmer extends Maintainer { + + private final OwnershipIssues ownershipIssues; + + public ApplicationOwnershipConfirmer(Controller controller, Duration interval, JobControl jobControl, OwnershipIssues ownershipIssues) { + super(controller, interval, jobControl); + this.ownershipIssues = ownershipIssues; + } + + @Override + protected void maintain() { + confirmApplicationOwnerships(); + ensureConfirmationResponses(); + } + + /** File an ownership issue with the owners of all applications we know about. */ + private void confirmApplicationOwnerships() { + for (Application application : controller().applications().asList()) { + try { + Tenant tenant = ownerOf(application.id()); + Optional<IssueId> ourIssueId = application.ownershipIssueId(); + ourIssueId = tenant.tenantType() == TenantType.USER + ? ownershipIssues.confirmOwnership(ourIssueId, application.id(), userFor(tenant)) + : ownershipIssues.confirmOwnership(ourIssueId, application.id(), propertyIdFor(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); + } + } + } + + /** Escalate ownership issues which have not been closed before a defined amount of time has passed. */ + private void ensureConfirmationResponses() { + for (Application application : controller().applications().asList()) + application.ownershipIssueId().ifPresent(issueId -> { + try { + ownershipIssues.ensureResponse(issueId, ownerOf(application.id()).getPropertyId()); + } + catch (RuntimeException e) { + log.log(Level.WARNING, "Exception caught when attempting to escalate issue with id " + issueId, e); + } + }); + } + + private Tenant ownerOf(ApplicationId applicationId) { + return controller().tenants().tenant(new TenantId(applicationId.tenant().value())) + .orElseThrow(() -> new IllegalStateException("No tenant found for application " + applicationId)); + } + + protected User userFor(Tenant tenant) { + return User.from(tenant.getId().id().replaceFirst("by-", "")); + } + + protected PropertyId propertyIdFor(Tenant tenant) { + return tenant.getPropertyId() + .orElseThrow(() -> new NoSuchElementException("No PropertyId is listed for non-user tenant " + tenant)); + } + + protected void store(IssueId issueId, ApplicationId applicationId) { + try (Lock lock = controller().applications().lock(applicationId)) { + controller().applications().get(applicationId, lock) + .ifPresent(application -> controller().applications().store(application.withOwnershipIssueId(issueId))); + } + } +} 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 2fdce2802ab..4acda712984 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.api.integration.organization.OwnershipIssues; import com.yahoo.vespa.hosted.controller.api.integration.organization.DeploymentIssues; import com.yahoo.vespa.hosted.controller.api.integration.chef.Chef; import com.yahoo.vespa.hosted.controller.maintenance.config.MaintainerConfig; @@ -34,11 +35,12 @@ public class ControllerMaintenance extends AbstractComponent { private final ClusterInfoMaintainer clusterInfoMaintainer; private final ClusterUtilizationMaintainer clusterUtilizationMaintainer; private final DeploymentMetricsMaintainer deploymentMetricsMaintainer; + private final ApplicationOwnershipConfirmer applicationOwnershipConfirmer; @SuppressWarnings("unused") // instantiated by Dependency Injection public ControllerMaintenance(MaintainerConfig maintainerConfig, Controller controller, CuratorDb curator, JobControl jobControl, Metric metric, Chef chefClient, - DeploymentIssues deploymentIssues) { + DeploymentIssues deploymentIssues, OwnershipIssues ownershipIssues) { Duration maintenanceInterval = Duration.ofMinutes(maintainerConfig.intervalMinutes()); this.jobControl = jobControl; deploymentExpirer = new DeploymentExpirer(controller, maintenanceInterval, jobControl); @@ -53,6 +55,7 @@ public class ControllerMaintenance extends AbstractComponent { clusterInfoMaintainer = new ClusterInfoMaintainer(controller, Duration.ofHours(2), jobControl); clusterUtilizationMaintainer = new ClusterUtilizationMaintainer(controller, Duration.ofHours(2), jobControl); deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, Duration.ofMinutes(10), jobControl); + applicationOwnershipConfirmer = new ApplicationOwnershipConfirmer(controller, Duration.ofHours(1), jobControl, ownershipIssues); } public Upgrader upgrader() { return upgrader; } @@ -74,6 +77,7 @@ public class ControllerMaintenance extends AbstractComponent { clusterUtilizationMaintainer.deconstruct(); clusterInfoMaintainer.deconstruct(); deploymentMetricsMaintainer.deconstruct(); + applicationOwnershipConfirmer.deconstruct(); } } 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 b4708dccb6b..4ab1426539d 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 @@ -67,7 +67,7 @@ public class DeploymentIssueReporter extends Maintainer { if (failingApplications.contains(application.id())) fileDeploymentIssueFor(application.id()); else - storeIssueId(application.id(), null); + store(application.id(), null); } /** @@ -111,7 +111,7 @@ public class DeploymentIssueReporter extends Maintainer { IssueId issueId = tenant.tenantType() == TenantType.USER ? deploymentIssues.fileUnlessOpen(ourIssueId, applicationId, userFor(tenant)) : deploymentIssues.fileUnlessOpen(ourIssueId, applicationId, propertyIdFor(tenant)); - storeIssueId(applicationId, issueId); + store(applicationId, issueId); } 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 " + applicationId, e); @@ -130,7 +130,7 @@ public class DeploymentIssueReporter extends Maintainer { })); } - private void storeIssueId(ApplicationId id, IssueId issueId) { + private void store(ApplicationId id, IssueId issueId) { try (Lock lock = controller().applications().lock(id)) { controller().applications().get(id, lock).ifPresent( application -> controller().applications().store(application.with(issueId)) 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 130d6f92d59..d294ad5dad8 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 @@ -51,6 +51,7 @@ public class ApplicationSerializer { private final String deploymentJobsField = "deploymentJobs"; private final String deployingField = "deployingField"; private final String outstandingChangeField = "outstandingChangeField"; + private final String ownershipIssueIdField = "ownershipIssueId"; // Deployment fields private final String zoneField = "zone"; @@ -123,6 +124,7 @@ public class ApplicationSerializer { toSlime(application.deploymentJobs(), root.setObject(deploymentJobsField)); toSlime(application.deploying(), root); root.setBool(outstandingChangeField, application.hasOutstandingChange()); + application.ownershipIssueId().ifPresent(issueId -> root.setString(ownershipIssueIdField, issueId.value())); return slime; } @@ -257,9 +259,10 @@ public class ApplicationSerializer { DeploymentJobs deploymentJobs = deploymentJobsFromSlime(root.field(deploymentJobsField)); Optional<Change> deploying = changeFromSlime(root.field(deployingField)); boolean outstandingChange = root.field(outstandingChangeField).asBool(); + Optional<IssueId> ownershipIssueId = optionalString(root.field(ownershipIssueIdField)).map(IssueId::from); return new Application(id, deploymentSpec, validationOverrides, deployments, - deploymentJobs, deploying, outstandingChange); + deploymentJobs, deploying, outstandingChange, ownershipIssueId); } private List<Deployment> deploymentsFromSlime(Inspector array) { 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 new file mode 100644 index 00000000000..25daf81b319 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationOwnershipConfirmerTest.java @@ -0,0 +1,107 @@ +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.ControllerTester; +import com.yahoo.vespa.hosted.controller.api.Tenant; +import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId; +import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId; +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; +import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; +import org.junit.Before; +import org.junit.Test; + +import java.time.Duration; +import java.util.Optional; +import java.util.function.Supplier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @#author jvenstad + */ +public class ApplicationOwnershipConfirmerTest { + + private MockOwnershipIssues issues; + private ApplicationOwnershipConfirmer confirmer; + private ControllerTester tester; + + @Before + public void setup() { + tester = new ControllerTester(); + issues = new MockOwnershipIssues(); + confirmer = new ApplicationOwnershipConfirmer(tester.controller(), Duration.ofDays(1), new JobControl(new MockCuratorDb()), issues); + } + + + @Test + public void testConfirmation() { + TenantId property = tester.createTenant("tenant", "domain", 1L); + ApplicationId propertyAppId = tester.createApplication(property, "application", "default", 1).id(); + Supplier<Application> propertyApp = () -> tester.controller().applications().require(propertyAppId); + + TenantId user = new TenantId("by-user"); + tester.controller().tenants().addTenant(Tenant.createUserTenant(new TenantId("by-user")), Optional.empty()); + assertTrue(tester.controller().tenants().tenant(user).isPresent()); + ApplicationId userAppId = tester.createApplication(user, "application", "default", 1).id(); + Supplier<Application> userApp = () -> tester.controller().applications().require(userAppId); + + 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); + + // Set response from the issue mock, which will be obtained by the maintainer on issue filing. + Optional<IssueId> issueId = Optional.of(IssueId.from("1")); + issues.response = issueId; + confirmer.maintain(); + confirmer.maintain(); + + assertEquals("Confirmation issue has been filed for property owned application.", propertyApp.get().ownershipIssueId(), issueId); + assertEquals("Confirmation issue has been filed for user owned application.", userApp.get().ownershipIssueId(), issueId); + assertTrue("Both applications have had their responses ensured.", issues.escalatedForProperty && issues.escalatedForUser); + + // No new issue is created, so return empty now. + issues.response = Optional.empty(); + confirmer.maintain(); + confirmer.maintain(); + + assertEquals("Confirmation issue reference is not updated when no issue id is returned.", propertyApp.get().ownershipIssueId(), issueId); + + // Time has passed, and a new confirmation issue is in order. + Optional<IssueId> issueId2 = Optional.of(IssueId.from("2")); + issues.response = issueId2; + confirmer.maintain(); + confirmer.maintain(); + + assertEquals("A new confirmation issue id is stored when something is returned to the maintainer.", propertyApp.get().ownershipIssueId(), issueId2); + } + + private class MockOwnershipIssues implements OwnershipIssues { + + private Optional<IssueId> response; + private boolean escalatedForProperty = false; + private boolean escalatedForUser = false; + + @Override + public Optional<IssueId> confirmOwnership(Optional<IssueId> issueId, ApplicationId applicationId, PropertyId propertyId) { + 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; + } + + } + +} 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 41cf7a331bb..e57edcf6da0 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 @@ -54,7 +54,7 @@ public class DeploymentIssueReporterTest { public void setup() { tester = new DeploymentTester(); issues = new MockDeploymentIssues(); - reporter = new DeploymentIssueReporter(tester.controller(), issues, Duration.ofMinutes(5), new JobControl(new MockCuratorDb())); + reporter = new DeploymentIssueReporter(tester.controller(), issues, Duration.ofDays(1), new JobControl(new MockCuratorDb())); } @Test 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 daccab8efbf..c737308e247 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 @@ -13,6 +13,7 @@ import com.yahoo.slime.Slime; import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.ControllerTester; +import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; import com.yahoo.vespa.hosted.controller.application.ApplicationRevision; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.ClusterInfo; @@ -82,7 +83,8 @@ public class ApplicationSerializerTest { validationOverrides, deployments, deploymentJobs, Optional.of(new Change.VersionChange(Version.fromString("6.7"))), - true); + true, + Optional.of(IssueId.from("1234"))); Application serialized = applicationSerializer.fromSlime(applicationSerializer.toSlime(original)); @@ -108,6 +110,8 @@ public class ApplicationSerializerTest { assertEquals(original.hasOutstandingChange(), serialized.hasOutstandingChange()); + assertEquals(original.ownershipIssueId(), serialized.ownershipIssueId()); + assertEquals(original.deploying(), serialized.deploying()); // Test cluster utilization 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 e6c0ce9027d..25b7d51b84f 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 @@ -43,6 +43,7 @@ public class ControllerContainerTest { " <component id='com.yahoo.vespa.hosted.controller.api.integration.github.GitHubMock'/>" + " <component id='com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService'/>" + " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.LoggingDeploymentIssues'/>" + + " <component id='com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues'/>" + " <component id='com.yahoo.vespa.hosted.controller.api.integration.organization.MockOrganization'/>" + " <component id='com.yahoo.vespa.hosted.controller.ConfigServerClientMock'/>" + " <component id='com.yahoo.vespa.hosted.controller.ZoneRegistryMock'/>" + diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index 3633860772b..31353e8a113 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -13,6 +13,9 @@ "name": "FailureRedeployer" }, { + "name": "ApplicationOwnershipConfirmer" + }, + { "name": "VersionStatusUpdater" }, { |