diff options
5 files changed, 46 insertions, 5 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java index 9b44c984324..a5938c3b6b5 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationStore.java @@ -27,9 +27,14 @@ public interface ApplicationStore { /** Removes diffs for packages before the given build number */ void pruneDiffs(TenantName tenantName, ApplicationName applicationName, long beforeBuildNumber); - /** Find application package by given build number */ + /** Find prod application package by given build number */ Optional<byte[]> find(TenantName tenant, ApplicationName application, long buildNumber); + /** Whether the prod application package with the given number is stored. */ + default boolean hasBuild(TenantName tenant, ApplicationName application, long buildNumber) { + return find(tenant, application, buildNumber).isPresent(); + } + /** Stores the given tenant application package of the given version and diff since previous version. */ void put(TenantName tenant, ApplicationName application, ApplicationVersion applicationVersion, byte[] applicationPackage, byte[] diff); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java index 1f387a49a68..a0dee6c059f 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/deployment/ApplicationVersion.java @@ -73,21 +73,21 @@ public class ApplicationVersion implements Comparable<ApplicationVersion> { Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), false); } - /** Creates an version from a completed build, an author email, and build meta data. */ + /** Creates a version from a completed build, an author email, and build meta data. */ public static ApplicationVersion from(SourceRevision source, long buildNumber, String authorEmail, Version compileVersion, Instant buildTime) { return new ApplicationVersion(Optional.of(source), OptionalLong.of(buildNumber), Optional.of(authorEmail), Optional.of(compileVersion), Optional.of(buildTime), Optional.empty(), Optional.empty(), false); } - /** Creates an version from a completed build, an author email, and build meta data. */ + /** Creates a version from a completed build, an author email, and build meta data. */ public static ApplicationVersion from(Optional<SourceRevision> source, long buildNumber, Optional<String> authorEmail, Optional<Version> compileVersion, Optional<Instant> buildTime, Optional<String> sourceUrl, Optional<String> commit, boolean deployedDirectly) { return new ApplicationVersion(source, OptionalLong.of(buildNumber), authorEmail, compileVersion, buildTime, sourceUrl, commit, deployedDirectly); } - /** Returns an unique identifier for this version or "unknown" if version is not known */ + /** Returns a unique identifier for this version or "unknown" if version is not known */ public String id() { if (isUnknown()) return "unknown"; 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 1046737d860..ed16c86c94e 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 @@ -1776,15 +1776,37 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { /** Trigger deployment to the last known application package for the given application. */ private HttpResponse deployApplication(String tenantName, String applicationName, String instanceName, HttpRequest request) { ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName); + Inspector buildField = toSlime(request.getData()).get().field("build"); + long build = buildField.valid() ? buildField.asLong() : -1; + StringBuilder response = new StringBuilder(); controller.applications().lockApplicationOrThrow(TenantAndApplicationId.from(id), application -> { - Change change = Change.of(application.get().latestVersion().get()); + ApplicationVersion version = build == -1 ? application.get().latestVersion().get() + : getApplicationVersion(application.get(), build); + Change change = Change.of(version); controller.applications().deploymentTrigger().forceChange(id, change); response.append("Triggered ").append(change).append(" for ").append(id); }); return new MessageResponse(response.toString()); } + private ApplicationVersion getApplicationVersion(Application application, Long build) { + // Check whether this is the latest version, and possibly return that. + // Otherwise, look through historic runs for a proper ApplicationVersion. + return application.latestVersion() + .filter(version -> version.buildNumber().stream().anyMatch(build::equals)) + .or(() -> controller.jobController().deploymentStatus(application).jobs() + .asList().stream() + .flatMap(job -> job.runs().values().stream()) + .map(run -> run.versions().targetApplication()) + .filter(version -> version.buildNumber().stream().anyMatch(build::equals)) + .findAny()) + .filter(version -> controller.applications().applicationStore().hasBuild(application.id().tenant(), + application.id().application(), + build)) + .orElseThrow(() -> new IllegalArgumentException("Build number '" + build + "' was not found")); + } + /** Cancel ongoing change for given application, e.g., everything with {"cancel":"all"} */ private HttpResponse cancelDeploy(String tenantName, String applicationName, String instanceName, String choice) { ApplicationId id = ApplicationId.from(tenantName, applicationName, instanceName); 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 afd67824ee8..8b8a7fc0c62 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 @@ -525,6 +525,17 @@ public class ApplicationApiTest extends ControllerContainerTest { .userIdentity(USER_ID), new File("proton-metrics.json")); + // POST a roll-out of the latest application + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying/application", POST) + .userIdentity(USER_ID), + "{\"message\":\"Triggered application change to 1.0.1-commit1 for tenant1.application1.instance1\"}"); + + // POST a roll-out of a given revision + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying/application", POST) + .data("{ \"build\": 1 }") + .userIdentity(USER_ID), + "{\"message\":\"Triggered application change to 1.0.1-commit1 for tenant1.application1.instance1\"}"); + // DELETE (cancel) ongoing change tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/deploying", DELETE) .userIdentity(HOSTED_VESPA_OPERATOR), diff --git a/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp index 8b34775b65d..2bccbe468ce 100644 --- a/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/executor_explorer_utils.cpp @@ -85,6 +85,9 @@ convert_executor_to_slime(const ThreadExecutor* executor, Cursor& object) void convert_executor_to_slime(const ISequencedTaskExecutor* executor, Cursor& object) { + if (executor == nullptr) { + return; + } if (const auto* seq = dynamic_cast<const SequencedTaskExecutor*>(executor)) { convert_sequenced_executor_to_slime(*seq, object); } else if (const auto* ada = dynamic_cast<const AdaptiveSequencedExecutor*>(executor)) { |