From f202879931f279d5602299aa63c8116d74440479 Mon Sep 17 00:00:00 2001 From: gjoranv Date: Tue, 9 Jun 2020 11:38:01 +0200 Subject: Add maintainer for downloading missing application packages. - Not yet enabled --- .../config/server/filedistribution/FileServer.java | 3 +- .../maintenance/ApplicationPackageMaintainer.java | 86 ++++++++++++++++++++++ .../yahoo/vespa/config/server/session/Session.java | 2 +- 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java (limited to 'configserver') diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java index 805ee2bef95..1e7f9fd69e7 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java @@ -199,8 +199,9 @@ public class FileServer { downloader.close(); } + // TODO: move to e.g. a util class // Connection pool with all config servers except this one (might be an empty pool if there is only one config server) - private static ConnectionPool createConnectionPool(ConfigserverConfig configserverConfig) { + public static ConnectionPool createConnectionPool(ConfigserverConfig configserverConfig) { List configServers = ConfigServerSpec.fromConfig(configserverConfig) .stream() .filter(spec -> !spec.getHostName().equals(HostName.getLocalhost())) diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java new file mode 100644 index 00000000000..2a00a175fd8 --- /dev/null +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java @@ -0,0 +1,86 @@ +package com.yahoo.vespa.config.server.maintenance; + +import com.yahoo.cloud.config.ConfigserverConfig; +import com.yahoo.config.FileReference; +import com.yahoo.vespa.config.server.ApplicationRepository; +import com.yahoo.vespa.config.server.filedistribution.FileServer; +import com.yahoo.vespa.config.server.session.RemoteSession; +import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.defaults.Defaults; +import com.yahoo.vespa.filedistribution.FileDownloader; +import com.yahoo.vespa.flags.BooleanFlag; +import com.yahoo.vespa.flags.FlagSource; +import com.yahoo.vespa.flags.Flags; + +import java.io.File; +import java.time.Duration; +import java.util.Set; +import java.util.logging.Logger; + +import static com.yahoo.vespa.config.server.ApplicationRepository.getFileReferencesOnDisk; + +/** + * Verifies that all active sessions has an application package on local disk. + * If not, the package is downloaded with file distribution. This can happen e.g. + * if a configserver is down when the application is deployed. + * + * @author gjoranv + */ +public class ApplicationPackageMaintainer extends ConfigServerMaintainer { + private static final Logger log = Logger.getLogger(ApplicationPackageMaintainer.class.getName()); + + private final ApplicationRepository applicationRepository; + private final ConfigserverConfig configserverConfig; + private final File downloadDirectory; + private final BooleanFlag distributeApplicationPackage; + + public ApplicationPackageMaintainer(ApplicationRepository applicationRepository, + Curator curator, + Duration interval, + ConfigserverConfig configserverConfig, + FlagSource flagSource) { + super(applicationRepository, curator, interval, interval); + this.applicationRepository = applicationRepository; + this.configserverConfig = configserverConfig; + + distributeApplicationPackage = Flags.CONFIGSERVER_DISTRIBUTE_APPLICATION_PACKAGE.bindTo(flagSource); + downloadDirectory = new File(Defaults.getDefaults().underVespaHome(configserverConfig.fileReferencesDir())); + if (distributeApplicationPackage.value()) assertDownloadDirectoryIsDefault(downloadDirectory); + } + + @Override + protected void maintain() { + if (! distributeApplicationPackage.value()) return; + + var fileDownloader = new FileDownloader(FileServer.createConnectionPool(configserverConfig)); + try { + for (var applicationId : applicationRepository.listApplications()) { + RemoteSession session = applicationRepository.getActiveSession(applicationId); + FileReference applicationPackage = session.getApplicationPackageReference(); + + if (applicationPackage != null && missingOnDisk(applicationPackage)) { + log.fine(() -> "Downloading missing application package for application " + applicationId + " - session " + session.getSessionId()); + + if (fileDownloader.getFile(applicationPackage).isEmpty()) { + log.warning("Failed to download application package for application " + applicationId + " - session " + session.getSessionId()); + } + } + } + } finally { + fileDownloader.close(); + } + } + + private boolean missingOnDisk(FileReference applicationPackageReference) { + Set fileReferencesOnDisk = getFileReferencesOnDisk(downloadDirectory); + return ! fileReferencesOnDisk.contains(applicationPackageReference.value()); + } + + // Required to use FileDownloader because it has no public ctor that takes a directory. + private static void assertDownloadDirectoryIsDefault(File fileReferencesDir) { + if (fileReferencesDir != FileDownloader.defaultDownloadDirectory) throw new IllegalArgumentException( + "Files must be downloaded to the default download directory (" + + FileDownloader.defaultDownloadDirectory + "), not " + fileReferencesDir); + } + +} diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java index 8b078f152f3..c553133ba12 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java @@ -107,7 +107,7 @@ public abstract class Session implements Comparable { public ApplicationId getApplicationId() { return zooKeeperClient.readApplicationId(); } - FileReference getApplicationPackageReference() {return zooKeeperClient.readApplicationPackageReference(); } + public FileReference getApplicationPackageReference() {return zooKeeperClient.readApplicationPackageReference(); } public Optional getDockerImageRepository() { return zooKeeperClient.readDockerImageRepository(); } -- cgit v1.2.3