diff options
Diffstat (limited to 'controller-server/src/main/java/com/yahoo')
4 files changed, 68 insertions, 27 deletions
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 3fad76b2e07..bc31a0a02fa 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 @@ -37,6 +37,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.PrepareRes import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; @@ -286,9 +287,65 @@ public class ApplicationController { return deploy(applicationId, zone, applicationPackageFromDeployer, Optional.empty(), options); } - /** Deploys an application. If the application does not exist it is created. */ - // TODO: Get rid of the options arg - // TODO jonmv: Split this, and choose between deployDirectly and deploy in handler, excluding internally built from the latter. + /** Deploys an application package for an existing application instance. */ + public ActivateResult deploy2(JobId job, boolean deploySourceVersions) { // TODO jonmv: make it number one! + if (job.application().instance().isTester()) + throw new IllegalArgumentException("'" + job.application() + "' is a tester application!"); + + TenantAndApplicationId applicationId = TenantAndApplicationId.from(job.application()); + ZoneId zone = job.type().zone(controller.system()); + + try (Lock deploymentLock = lockForDeployment(job.application(), zone)) { + Set<ContainerEndpoint> endpoints; + Optional<EndpointCertificateMetadata> endpointCertificateMetadata; + + Run run = controller.jobController().last(job) + .orElseThrow(() -> new IllegalStateException("No known run of '" + job + "'")); + + if (run.hasEnded()) + throw new IllegalStateException("No deployment expected for " + job + " now, as no job is running"); + + Version platform = run.versions().sourcePlatform().filter(__ -> deploySourceVersions).orElse(run.versions().targetPlatform()); + ApplicationVersion revision = run.versions().sourceApplication().filter(__ -> deploySourceVersions).orElse(run.versions().targetApplication()); + ApplicationPackage applicationPackage = getApplicationPackage(job.application(), zone, revision); + + try (Lock lock = lock(applicationId)) { + LockedApplication application = new LockedApplication(requireApplication(applicationId), lock); + Instance instance = application.get().require(job.application().instance()); + + Deployment deployment = instance.deployments().get(zone); + if ( zone.environment().isProduction() && deployment != null + && ( platform.compareTo(deployment.version()) < 0 && ! instance.change().isPinned() + || revision.compareTo(deployment.applicationVersion()) < 0 && ! (revision.isUnknown() && controller.system().isCd()))) + throw new IllegalArgumentException(String.format("Rejecting deployment of application %s to %s, as the requested versions (platform: %s, application: %s)" + + " are older than the currently deployed (platform: %s, application: %s).", + job.application(), zone, platform, revision, deployment.version(), deployment.applicationVersion())); + + if ( ! applicationPackage.trustedCertificates().isEmpty() + && run.testerCertificate().isPresent()) + applicationPackage = applicationPackage.withTrustedCertificate(run.testerCertificate().get()); + + endpointCertificateMetadata = endpointCertificateManager.getEndpointCertificateMetadata(instance, zone); + + endpoints = controller.routing().registerEndpointsInDns(applicationPackage.deploymentSpec(), instance, zone); + } // Release application lock while doing the deployment, which is a lengthy task. + + // Carry out deployment without holding the application lock. + ActivateResult result = deploy(job.application(), applicationPackage, zone, platform, endpoints, endpointCertificateMetadata); + + lockApplicationOrThrow(applicationId, application -> + store(application.with(job.application().instance(), + instance -> instance.withNewDeployment(zone, revision, platform, + clock.instant(), warningsFrom(result))))); + return result; + } + } + + private ApplicationPackage getApplicationPackage(ApplicationId application, ZoneId zone, ApplicationVersion revision) { + return new ApplicationPackage(revision.isUnknown() ? applicationStore.getDev(application, zone) + : applicationStore.get(application.tenant(), application.application(), revision)); + } + public ActivateResult deploy(ApplicationId instanceId, ZoneId zone, Optional<ApplicationPackage> applicationPackageFromDeployer, Optional<ApplicationVersion> applicationVersionFromDeployer, diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java index 861c8089ed5..628a7e41eb2 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java @@ -173,34 +173,20 @@ public class InternalStepRunner implements StepRunner { versions.sourcePlatform().orElse(versions.targetPlatform()) + " and application version " + versions.sourceApplication().orElse(versions.targetApplication()).id() + " ..."); - return deployReal(id, true, versions, logger); + return deployReal(id, true, logger); } private Optional<RunStatus> deployReal(RunId id, DualLogger logger) { Versions versions = controller.jobController().run(id).get().versions(); logger.log("Deploying platform version " + versions.targetPlatform() + " and application version " + versions.targetApplication().id() + " ..."); - return deployReal(id, false, versions, logger); + return deployReal(id, false, logger); } - private Optional<RunStatus> deployReal(RunId id, boolean setTheStage, Versions versions, DualLogger logger) { - Optional<ApplicationPackage> applicationPackage = id.type().environment().isManuallyDeployed() - ? Optional.of(new ApplicationPackage(controller.applications().applicationStore() - .getDev(id.application(), id.type().zone(controller.system())))) - : Optional.empty(); - - Optional<Version> vespaVersion = id.type().environment().isManuallyDeployed() - ? Optional.of(versions.targetPlatform()) // TODO jonmv: This makes it impossible to deploy on older majors — fix. - : Optional.empty(); + private Optional<RunStatus> deployReal(RunId id, boolean setTheStage, DualLogger logger) { return deploy(id.application(), id.type(), - () -> controller.applications().deploy(id.application(), - id.type().zone(controller.system()), - applicationPackage, - new DeployOptions(false, - vespaVersion, - false, - setTheStage)), + () -> controller.applications().deploy2(id.job(), setTheStage), controller.jobController().run(id).get() .stepInfo(setTheStage ? deployInitialReal : deployReal).get() .startTime().get(), diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java index 007654b2a7c..5d8ad6594df 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java @@ -418,9 +418,6 @@ public class JobController { /** Orders a run of the given type, or throws an IllegalStateException if that job type is already running. */ public void start(ApplicationId id, JobType type, Versions versions, JobProfile profile) { - if (profile != JobProfile.development && versions.targetApplication().isUnknown()) - throw new IllegalArgumentException(" Target application must be a valid reference"); - controller.applications().lockApplicationIfPresent(TenantAndApplicationId.from(id), application -> { locked(id, type, __ -> { Optional<Run> last = last(id, type); @@ -436,9 +433,6 @@ public class JobController { /** Stores the given package and starts a deployment of it, after aborting any such ongoing deployment. */ public void deploy(ApplicationId id, JobType type, Optional<Version> platform, ApplicationPackage applicationPackage) { - if ( ! type.environment().isManuallyDeployed()) - throw new IllegalArgumentException("Direct deployments are only allowed to manually deployed environments."); - controller.applications().lockApplicationOrThrow(TenantAndApplicationId.from(id), application -> { if ( ! application.get().instances().containsKey(id.instance())) application = controller.applications().withNewInstance(application, id); @@ -546,6 +540,7 @@ public class JobController { application.get().productionDeployments().values().stream() .flatMap(List::stream) .map(Deployment::applicationVersion) + .filter(version -> ! version.isUnknown()) .min(Comparator.comparingLong(applicationVersion -> applicationVersion.buildNumber().getAsLong())) .ifPresent(oldestDeployed -> { controller.applications().applicationStore().prune(id.tenant(), id.application(), oldestDeployed); 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 1c8279f6d8d..7b2e1ad7a8e 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 @@ -1482,6 +1482,9 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } private HttpResponse jobDeploy(ApplicationId id, JobType type, HttpRequest request) { + if ( ! type.environment().isManuallyDeployed() && ! isOperator(request)) + throw new IllegalArgumentException("Direct deployments are only allowed to manually deployed environments."); + Map<String, byte[]> dataParts = parseDataParts(request); if ( ! dataParts.containsKey("applicationZip")) throw new IllegalArgumentException("Missing required form part 'applicationZip'"); |