summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
Diffstat (limited to 'configserver')
-rw-r--r--configserver/pom.xml10
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/PathProvider.java42
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKTenantApplications.java27
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java15
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/AddFileInterface.java9
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/ApplicationFileManager.java25
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyDistribution.java30
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyRegistry.java32
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBHandler.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBRegistry.java24
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDirectory.java120
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionProvider.java33
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java145
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/MockFileDBHandler.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/Utils.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpConfigRequests.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java16
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponses.java17
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/rpc/RpcServer.java88
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionFactory.java8
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionRepo.java20
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java4
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java21
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantBuilder.java20
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/Tenants.java53
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/SessionCounter.java9
-rw-r--r--configserver/src/main/resources/configserver-app/services.xml4
-rwxr-xr-xconfigserver/src/main/sh/vespa-configserver-remove-state11
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/InjectedGlobalComponentRegistryTest.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java1
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java83
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java36
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/filedistribution/FileServerTest.java112
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/CompressedApplicationInputStreamTest.java27
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionActiveHandlerTest.java9
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java27
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java30
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TenantTest.java3
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TestTenantBuilder.java11
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java5
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponseTest.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpc.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/rpc/TestWithRpc.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionRepoTest.java13
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java14
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/MockSessionZKClient.java14
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java71
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionTest.java17
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java1
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionRepoTest.java8
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandlerTest.java10
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantsTestCase.java40
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TestWithTenant.java4
-rw-r--r--configserver/src/test/resources/deploy/advancedapp/deployment.xml1
-rw-r--r--configserver/src/test/resources/deploy/app/deployment.xml1
-rw-r--r--configserver/src/test/resources/deploy/validapp/deployment.xml1
58 files changed, 1004 insertions, 356 deletions
diff --git a/configserver/pom.xml b/configserver/pom.xml
index 8776fbd5ad1..30d92dc7650 100644
--- a/configserver/pom.xml
+++ b/configserver/pom.xml
@@ -126,6 +126,11 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
+ <artifactId>filedistribution</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
<artifactId>filedistributionmanager</artifactId>
<version>${project.version}</version>
</dependency>
@@ -172,6 +177,11 @@
<artifactId>jersey-proxy-client</artifactId>
</dependency>
<dependency>
+ <groupId>net.jpountz.lz4</groupId>
+ <artifactId>lz4</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/PathProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/PathProvider.java
deleted file mode 100644
index 5910c69048a..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/PathProvider.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.config.server;
-
-import com.google.inject.Inject;
-import com.yahoo.path.Path;
-
-/**
- * Temporary provider of root path for components that will soon get them injected from a parent class.
- *
- * @author lulf
- * * @since 5.1.24
- */
-public class PathProvider {
-
- private final Path root;
- // Path for Vespa-related data stored in Zookeeper (subpaths are relative to this path)
- // NOTE: This should not be exposed, as this path can be different in testing, depending on how we configure it.
- private static final String APPS_ZK_NODE = "sessions";
- private static final String VESPA_ZK_PATH = "/vespa/config";
-
- @Inject
- public PathProvider() {
- root = Path.fromString(VESPA_ZK_PATH);
- }
-
- public PathProvider(Path root) {
- this.root = root;
- }
-
- public Path getRoot() {
- return root;
- }
-
- public Path getSessionDirs() {
- return root.append(APPS_ZK_NODE);
- }
-
- public Path getSessionDir(long sessionId) {
- return getSessionDirs().append(String.valueOf(sessionId));
- }
-
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKTenantApplications.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKTenantApplications.java
index 648e6bb7180..c3d13b86591 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKTenantApplications.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKTenantApplications.java
@@ -18,11 +18,15 @@ import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
@@ -36,10 +40,13 @@ import java.util.logging.Logger;
public class ZKTenantApplications implements TenantApplications, PathChildrenCacheListener {
private static final Logger log = Logger.getLogger(ZKTenantApplications.class.getName());
+ private static final Duration checkForRemovedApplicationsInterval = Duration.ofMinutes(1);
+
private final Curator curator;
private final Path applicationsPath;
private final ExecutorService pathChildrenExecutor =
Executors.newFixedThreadPool(1, ThreadFactoryFactory.getThreadFactory(ZKTenantApplications.class.getName()));
+ private final ScheduledExecutorService checkForRemovedApplicationsService = new ScheduledThreadPoolExecutor(1);
private final Curator.DirectoryCache directoryCache;
private final ReloadHandler reloadHandler;
private final TenantName tenant;
@@ -47,16 +54,21 @@ public class ZKTenantApplications implements TenantApplications, PathChildrenCac
private ZKTenantApplications(Curator curator, Path applicationsPath, ReloadHandler reloadHandler, TenantName tenant) {
this.curator = curator;
this.applicationsPath = applicationsPath;
+ curator.create(applicationsPath);
this.reloadHandler = reloadHandler;
this.tenant = tenant;
this.directoryCache = curator.createDirectoryCache(applicationsPath.getAbsolute(), false, false, pathChildrenExecutor);
this.directoryCache.start();
this.directoryCache.addListener(this);
+ checkForRemovedApplicationsService.scheduleWithFixedDelay(this::removeApplications,
+ checkForRemovedApplicationsInterval.getSeconds(),
+ checkForRemovedApplicationsInterval.getSeconds(),
+ TimeUnit.SECONDS);
}
- public static TenantApplications create(Curator curator, Path applicationsPath, ReloadHandler reloadHandler, TenantName tenant) {
+ public static TenantApplications create(Curator curator, ReloadHandler reloadHandler, TenantName tenant) {
try {
- return new ZKTenantApplications(curator, applicationsPath, reloadHandler, tenant);
+ return new ZKTenantApplications(curator, Tenants.getApplicationsPath(tenant), reloadHandler, tenant);
} catch (Exception e) {
throw new RuntimeException(Tenants.logPre(tenant) + "Error creating application repo", e);
}
@@ -118,6 +130,7 @@ public class ZKTenantApplications implements TenantApplications, PathChildrenCac
public void close() {
directoryCache.close();
pathChildrenExecutor.shutdown();
+ checkForRemovedApplicationsService.shutdown();
}
@Override
@@ -138,22 +151,22 @@ public class ZKTenantApplications implements TenantApplications, PathChildrenCac
}
// We might have lost events and might need to remove applications (new applications are
// not added by listening for events here, they are added when session is added, see RemoteSessionRepo)
- removeApplications(event.getType());
+ removeApplications();
}
private void applicationRemoved(ApplicationId applicationId) {
reloadHandler.removeApplication(applicationId);
- log.log(LogLevel.DEBUG, Tenants.logPre(applicationId) + "Application removed: " + applicationId);
+ log.log(LogLevel.INFO, Tenants.logPre(applicationId) + "Application removed: " + applicationId);
}
private void applicationAdded(ApplicationId applicationId) {
log.log(LogLevel.DEBUG, Tenants.logPre(applicationId) + "Application added: " + applicationId);
}
- private void removeApplications(PathChildrenCacheEvent.Type eventType) {
+ private void removeApplications() {
ImmutableSet<ApplicationId> activeApplications = ImmutableSet.copyOf(listApplications());
- log.log(LogLevel.DEBUG, "Got " + eventType + " event for tenant '" + tenant +
- "', removing applications except these active applications: " + activeApplications);
+ log.log(LogLevel.DEBUG, "Removing stale applications for tenant '" + tenant +
+ "', not removing these active applications: " + activeApplications);
reloadHandler.removeApplicationsExcept(activeApplications);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 70b677b4057..c0c9c309576 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -2,11 +2,16 @@
package com.yahoo.vespa.config.server.deploy;
import com.yahoo.component.Version;
-import com.yahoo.config.model.api.*;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.FileRegistry;
+import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.ConfigServerSpec;
+import com.yahoo.config.model.api.HostProvisioner;
+import com.yahoo.config.model.api.Model;
+import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.Rotation;
import com.yahoo.config.provision.Zone;
@@ -132,6 +137,7 @@ public class ModelContextImpl implements ModelContext {
private final ApplicationId applicationId;
private final boolean multitenant;
private final List<ConfigServerSpec> configServerSpecs;
+ private final HostName loadBalancerName;
private final boolean hostedVespa;
private final Zone zone;
private final Set<Rotation> rotations;
@@ -139,12 +145,14 @@ public class ModelContextImpl implements ModelContext {
public Properties(ApplicationId applicationId,
boolean multitenant,
List<ConfigServerSpec> configServerSpecs,
+ HostName loadBalancerName,
boolean hostedVespa,
Zone zone,
Set<Rotation> rotations) {
this.applicationId = applicationId;
this.multitenant = multitenant;
this.configServerSpecs = configServerSpecs;
+ this.loadBalancerName = loadBalancerName;
this.hostedVespa = hostedVespa;
this.zone = zone;
this.rotations = rotations;
@@ -166,6 +174,11 @@ public class ModelContextImpl implements ModelContext {
}
@Override
+ public HostName loadBalancerName() {
+ return loadBalancerName;
+ }
+
+ @Override
public boolean hostedVespa() {
return hostedVespa;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/AddFileInterface.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/AddFileInterface.java
new file mode 100644
index 00000000000..61c376a7256
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/AddFileInterface.java
@@ -0,0 +1,9 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.config.FileReference;
+
+public interface AddFileInterface {
+ FileReference addFile(String relativePath);
+ FileReference addFile(String relativePath, FileReference reference);
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/ApplicationFileManager.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/ApplicationFileManager.java
new file mode 100644
index 00000000000..0d1aae97690
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/ApplicationFileManager.java
@@ -0,0 +1,25 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.config.FileReference;
+import java.io.File;
+
+public class ApplicationFileManager implements AddFileInterface {
+ private final File applicationDir;
+ private final FileDirectory master;
+
+ ApplicationFileManager(File applicationDir, FileDirectory master) {
+ this.applicationDir = applicationDir;
+ this.master = master;
+ }
+
+ @Override
+ public FileReference addFile(String relativePath, FileReference reference) {
+ return master.addFile(new File(applicationDir, relativePath), reference);
+ }
+
+ @Override
+ public FileReference addFile(String relativePath) {
+ return master.addFile(new File(applicationDir, relativePath));
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyDistribution.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyDistribution.java
new file mode 100644
index 00000000000..588f2d1d63f
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyDistribution.java
@@ -0,0 +1,30 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.model.api.FileDistribution;
+
+import java.util.Collection;
+import java.util.Set;
+
+public class CombinedLegacyDistribution implements FileDistribution {
+ private final FileDistribution legacy;
+
+ CombinedLegacyDistribution(FileDBHandler legacy) {
+ this.legacy = legacy;
+ }
+ @Override
+ public void sendDeployedFiles(String hostName, Set<FileReference> fileReferences) {
+ legacy.sendDeployedFiles(hostName, fileReferences);
+ }
+
+ @Override
+ public void reloadDeployFileDistributor() {
+ legacy.reloadDeployFileDistributor();
+ }
+
+ @Override
+ public void removeDeploymentsThatHaveDifferentApplicationId(Collection<String> targetHostnames) {
+ legacy.removeDeploymentsThatHaveDifferentApplicationId(targetHostnames);
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyRegistry.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyRegistry.java
new file mode 100644
index 00000000000..8f2cb194bbd
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/CombinedLegacyRegistry.java
@@ -0,0 +1,32 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.application.api.FileRegistry;
+
+import java.util.List;
+
+public class CombinedLegacyRegistry implements FileRegistry {
+ private final FileDBRegistry legacy;
+ private final FileDBRegistry future;
+
+ CombinedLegacyRegistry(FileDBRegistry legacy, FileDBRegistry future) {
+ this.legacy = legacy;
+ this.future = future;
+ }
+ @Override
+ public FileReference addFile(String relativePath) {
+ FileReference reference = legacy.addFile(relativePath);
+ return future.addFile(relativePath, reference);
+ }
+
+ @Override
+ public String fileSourceHost() {
+ return future.fileSourceHost();
+ }
+
+ @Override
+ public List<Entry> export() {
+ return future.export();
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBHandler.java
index d7dce9d3f3d..f0ce6104496 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBHandler.java
@@ -31,11 +31,6 @@ public class FileDBHandler implements FileDistribution {
}
@Override
- public void limitSendingOfDeployedFilesTo(Collection<String> hostNames) {
- manager.limitSendingOfDeployedFilesTo(hostNames);
- }
-
- @Override
public void removeDeploymentsThatHaveDifferentApplicationId(Collection<String> targetHostnames) {
manager.removeDeploymentsThatHaveDifferentApplicationId(targetHostnames);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBRegistry.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBRegistry.java
index d921d8d4f8d..1a76454fbed 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBRegistry.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDBRegistry.java
@@ -4,29 +4,41 @@ package com.yahoo.vespa.config.server.filedistribution;
import com.yahoo.config.FileReference;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.net.HostName;
-import com.yahoo.vespa.filedistribution.FileDistributionManager;
-import com.yahoo.config.model.application.provider.FileReferenceCreator;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
/**
* @author tonytv
*/
public class FileDBRegistry implements FileRegistry {
- private final FileDistributionManager manager;
+ private final AddFileInterface manager;
private List<Entry> entries = new ArrayList<>();
private final Map<String, FileReference> fileReferenceCache = new HashMap<>();
- public FileDBRegistry(FileDistributionManager manager) {
+ public FileDBRegistry(AddFileInterface manager) {
this.manager = manager;
}
+ public synchronized FileReference addFile(String relativePath, FileReference reference) {
+ Optional<FileReference> cachedReference = Optional.ofNullable(fileReferenceCache.get(relativePath));
+ return cachedReference.orElseGet(() -> {
+ FileReference newRef = manager.addFile(relativePath, reference);
+ entries.add(new Entry(relativePath, newRef));
+ fileReferenceCache.put(relativePath, newRef);
+ return newRef;
+ });
+ }
+
@Override
public synchronized FileReference addFile(String relativePath) {
Optional<FileReference> cachedReference = Optional.ofNullable(fileReferenceCache.get(relativePath));
return cachedReference.orElseGet(() -> {
- FileReference newRef = FileReferenceCreator.create(manager.addFile(relativePath));
+ FileReference newRef = manager.addFile(relativePath);
entries.add(new Entry(relativePath, newRef));
fileReferenceCache.put(relativePath, newRef);
return newRef;
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDirectory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDirectory.java
new file mode 100644
index 00000000000..7d0ba6cd9bd
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDirectory.java
@@ -0,0 +1,120 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.model.api.FileDistribution;
+import com.yahoo.io.IOUtils;
+import com.yahoo.text.Utf8;
+import net.jpountz.xxhash.XXHash64;
+import net.jpountz.xxhash.XXHashFactory;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.logging.Logger;
+
+public class FileDirectory {
+ private static final Logger log = Logger.getLogger(FileDirectory.class.getName());
+ private final File root;
+
+ public FileDirectory() {
+ this(FileDistribution.getDefaultFileDBPath());
+ }
+
+ public FileDirectory(File rootDir) {
+ root = rootDir;
+ try {
+ ensureRootExist();
+ } catch (IllegalArgumentException e) {
+ log.warning("Failed creating directory in constructor, will retry on demand : " + e.toString());
+ }
+ }
+
+ private void ensureRootExist() {
+ if (! root.exists()) {
+ if ( ! root.mkdir()) {
+ throw new IllegalArgumentException("Failed creating root dir '" + root.getAbsolutePath() + "'.");
+ }
+ } else if (!root.isDirectory()) {
+ throw new IllegalArgumentException("'" + root.getAbsolutePath() + "' is not a directory");
+ }
+ }
+
+ static private class Filter implements FilenameFilter {
+ @Override
+ public boolean accept(File dir, String name) {
+ return !".".equals(name) && !"..".equals(name) ;
+ }
+ }
+
+ String getPath(FileReference ref) {
+ return root.getAbsolutePath() + "/" + ref.value();
+ }
+
+ File getFile(FileReference reference) {
+ ensureRootExist();
+ File dir = new File(getPath(reference));
+ if (!dir.exists()) {
+ throw new IllegalArgumentException("File reference '" + reference.toString() + "' with absolute path '" + dir.getAbsolutePath() + "' does not exist.");
+ }
+ if (!dir.isDirectory()) {
+ throw new IllegalArgumentException("File reference '" + reference.toString() + "' with absolute path '" + dir.getAbsolutePath() + "' is not a directory.");
+ }
+ File [] files = dir.listFiles(new Filter());
+ if (files.length != 1) {
+ StringBuilder msg = new StringBuilder();
+ for (File f: files) {
+ msg.append(f.getName()).append("\n");
+ }
+ throw new IllegalArgumentException("File reference '" + reference.toString() + "' with absolute path '" + dir.getAbsolutePath() + " does not contain exactly one file, but [" + msg.toString() + "]");
+ }
+ return files[0];
+ }
+
+ private Long computeReference(File file) throws IOException {
+ byte [] wholeFile = IOUtils.readFileBytes(file);
+ XXHash64 hasher = XXHashFactory.fastestInstance().hash64();
+ return hasher.hash(ByteBuffer.wrap(wholeFile), hasher.hash(ByteBuffer.wrap(Utf8.toBytes(file.getName())), 0));
+ }
+
+ public FileReference addFile(File source) {
+ try {
+ Long hash = computeReference(source);
+ FileReference reference = new FileReference(Long.toHexString(hash));
+ return addFile(source, reference);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public FileReference addFile(File source, FileReference reference) {
+ ensureRootExist();
+ try {
+ File destinationDir = new File(root, reference.value());
+ if (!destinationDir.exists()) {
+ destinationDir.mkdir();
+ Path tempDestinationDir = Files.createTempDirectory(root.toPath(), "writing");
+ File destination = new File(tempDestinationDir.toFile(), source.getName());
+ if (source.isDirectory())
+ IOUtils.copyDirectory(source, destination);
+ else
+ IOUtils.copy(source, destination);
+ if (!destinationDir.exists()) {
+ if ( ! tempDestinationDir.toFile().renameTo(destinationDir)) {
+ log.warning("Failed moving '" + tempDestinationDir.toFile().getAbsolutePath() + "' to '" + destination.getAbsolutePath() + "'.");
+ }
+ } else {
+ IOUtils.copyDirectory(tempDestinationDir.toFile(), destinationDir, 1);
+ }
+ IOUtils.recursiveDeleteDir(tempDestinationDir.toFile());
+ }
+ return reference;
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionProvider.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionProvider.java
index 3693bfb361c..59c3a54897d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionProvider.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionProvider.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.filedistribution;
+import com.yahoo.config.FileReference;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.vespa.filedistribution.FileDistributionManager;
@@ -19,16 +20,32 @@ public class FileDistributionProvider {
private final FileRegistry fileRegistry;
private final FileDistribution fileDistribution;
- public FileDistributionProvider(File applicationDir, String zooKeepersSpec, String applicationId, Lock fileDistributionLock) {
+ static private class ManagerWrapper implements AddFileInterface {
+ private final FileDistributionManager manager;
+ ManagerWrapper(FileDistributionManager manager) {
+ this.manager = manager;
+ }
+ @Override
+ public FileReference addFile(String relativePath) {
+ return new FileReference(manager.addFile(relativePath));
+ }
+
+ @Override
+ public FileReference addFile(String relativePath, FileReference reference) {
+ throw new IllegalStateException("addFile with external reference is not possible with legacy filedistribution.");
+ }
+ }
+
+ public FileDistributionProvider(File applicationDir, String zooKeepersSpec,
+ String applicationId, Lock fileDistributionLock)
+ {
ensureDirExists(FileDistribution.getDefaultFileDBPath());
final FileDistributionManager manager = new FileDistributionManager(
- FileDistribution.getDefaultFileDBPath(),
- applicationDir,
- zooKeepersSpec,
- applicationId,
- fileDistributionLock);
- this.fileDistribution = new FileDBHandler(manager);
- this.fileRegistry = new FileDBRegistry(manager);
+ FileDistribution.getDefaultFileDBPath(), applicationDir,
+ zooKeepersSpec, applicationId, fileDistributionLock);
+ this.fileDistribution = new CombinedLegacyDistribution(new FileDBHandler(manager));
+ this.fileRegistry = new CombinedLegacyRegistry(new FileDBRegistry(new ManagerWrapper(manager)),
+ new FileDBRegistry(new ApplicationFileManager(applicationDir, new FileDirectory())));
}
public FileDistributionProvider(FileRegistry fileRegistry, FileDistribution fileDistribution) {
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
new file mode 100644
index 00000000000..9316a9a5c8e
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileServer.java
@@ -0,0 +1,145 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.google.inject.Inject;
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.FileReference;
+import com.yahoo.config.model.api.FileDistribution;
+import com.yahoo.config.subscription.ConfigSourceSet;
+import com.yahoo.io.IOUtils;
+import com.yahoo.jrt.Supervisor;
+import com.yahoo.jrt.Transport;
+import com.yahoo.net.HostName;
+import com.yahoo.vespa.config.Connection;
+import com.yahoo.vespa.config.ConnectionPool;
+import com.yahoo.vespa.config.JRTConnectionPool;
+import com.yahoo.vespa.config.server.ConfigServerSpec;
+import com.yahoo.vespa.filedistribution.FileDownloader;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+public class FileServer {
+ private static final Logger log = Logger.getLogger(FileServer.class.getName());
+ private final FileDirectory root;
+ private final ExecutorService executor;
+ private final FileDownloader downloader;
+
+ public static class ReplayStatus {
+ private final int code;
+ private final String description;
+ public ReplayStatus(int code, String description) {
+ this.code = code;
+ this.description = description;
+ }
+ public boolean ok() { return code == 0; }
+ public int getCode() { return code; }
+ public String getDescription() { return description; }
+ }
+
+ public interface Receiver {
+ void receive(FileReference reference, String filename, byte [] content, ReplayStatus status);
+ }
+
+ @Inject
+ public FileServer(ConfigserverConfig configserverConfig) {
+ this(createConnectionPool(configserverConfig), FileDistribution.getDefaultFileDBPath());
+ }
+
+ // For testing only
+ public FileServer(File rootDir) {
+ this(new EmptyConnectionPool(), rootDir);
+ }
+
+ private FileServer(ConnectionPool connectionPool, File rootDir) {
+ this.downloader = new FileDownloader(connectionPool);
+ this.root = new FileDirectory(rootDir);
+ this.executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+ }
+
+ public boolean hasFile(String fileName) {
+ return hasFile(new FileReference(fileName));
+ }
+ public boolean hasFile(FileReference reference) {
+ try {
+ return root.getFile(reference).exists();
+ } catch (IllegalArgumentException e) {
+ log.warning("Failed locating file reference '" + reference + "' with error " + e.toString());
+ }
+ return false;
+ }
+ public boolean startFileServing(String fileName, Receiver target) {
+ FileReference reference = new FileReference(fileName);
+ File file = root.getFile(reference);
+
+ if (file.exists()) {
+ executor.execute(() -> serveFile(reference, target));
+ }
+ return false;
+ }
+
+ private void serveFile(FileReference reference, Receiver target) {
+ File file = root.getFile(reference);
+ // TODO remove once verified in system tests.
+ log.info("Start serving reference '" + reference.value() + "' with file '" + file.getAbsolutePath() + "'");
+ byte [] blob = new byte [0];
+ boolean success = false;
+ String errorDescription = "OK";
+ try {
+ blob = IOUtils.readFileBytes(file);
+ success = true;
+ } catch (IOException e) {
+ errorDescription = "For file reference '" + reference.value() + "' I failed reading file '" + file.getAbsolutePath() + "'";
+ log.warning(errorDescription + "for sending to '" + target.toString() + "'. " + e.toString());
+ }
+ target.receive(reference, file.getName(), blob,
+ new ReplayStatus(success ? 0 : 1, success ? "OK" : errorDescription));
+ // TODO remove once verified in system tests.
+ log.info("Done serving reference '" + reference.toString() + "' with file '" + file.getAbsolutePath() + "'");
+ }
+
+ public void download(FileReference fileReference) {
+ downloader.getFile(fileReference);
+ }
+
+ public FileDownloader downloader() {
+ return downloader;
+ }
+
+ // 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) {
+ List<String> configServers = ConfigServerSpec.fromConfig(configserverConfig)
+ .stream()
+ .filter(spec -> !spec.getHostName().equals(HostName.getLocalhost()))
+ .map(spec -> "tcp/" + spec.getHostName() + ":" + spec.getConfigServerPort())
+ .collect(Collectors.toList());
+
+ return configServers.size() > 0 ? new JRTConnectionPool(new ConfigSourceSet(configServers)) : new EmptyConnectionPool();
+ }
+
+ private static class EmptyConnectionPool implements ConnectionPool {
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void setError(Connection connection, int i) {}
+
+ @Override
+ public Connection getCurrent() { return null; }
+
+ @Override
+ public Connection setNewCurrentConnection() { return null; }
+
+ @Override
+ public int getSize() { return 0; }
+
+ @Override
+ public Supervisor getSupervisor() { return new Supervisor(new Transport()); }
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/MockFileDBHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/MockFileDBHandler.java
index 81c777df393..eb23d38e23e 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/MockFileDBHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/MockFileDBHandler.java
@@ -14,7 +14,6 @@ import java.util.Set;
public class MockFileDBHandler implements FileDistribution {
public int sendDeployedFilesCalled = 0;
public int reloadDeployFileDistributorCalled = 0;
- public int limitSendingOfDeployedFilesToCalled = 0;
public int removeDeploymentsThatHaveDifferentApplicationIdCalled = 0;
@Override
@@ -28,11 +27,6 @@ public class MockFileDBHandler implements FileDistribution {
}
@Override
- public void limitSendingOfDeployedFilesTo(Collection<String> hostNames) {
- limitSendingOfDeployedFilesToCalled++;
- }
-
- @Override
public void removeDeploymentsThatHaveDifferentApplicationId(Collection<String> targetHostnames) {
removeDeploymentsThatHaveDifferentApplicationIdCalled++;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/Utils.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/Utils.java
index 873a24b5f05..e5bf8e22020 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/Utils.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/Utils.java
@@ -31,9 +31,10 @@ public class Utils {
com.yahoo.jdisc.http.HttpRequest jDiscRequest = req.getJDiscRequest();
BindingMatch<?> bm = jDiscRequest.getBindingMatch();
if (bm == null) {
+ UriPattern pattern = new UriPattern(uriPattern);
bm = new BindingMatch<>(
- new UriPattern(uriPattern).match(URI.create(jDiscRequest.getUri().toString())),
- new Object());
+ pattern.match(URI.create(jDiscRequest.getUri().toString())),
+ new Object(), pattern);
}
return bm;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpConfigRequests.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpConfigRequests.java
index db92f53aacd..59270afd397 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpConfigRequests.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpConfigRequests.java
@@ -39,7 +39,7 @@ public class HttpConfigRequests {
UriPattern fullAppIdPattern = new UriPattern(pattern);
URI uri = req.getUri();
Match match = fullAppIdPattern.match(uri);
- if (match!=null) return new BindingMatch<>(match, new Object());
+ if (match!=null) return new BindingMatch<>(match, new Object(), fullAppIdPattern);
}
throw new IllegalArgumentException("Illegal url for config request: " + req.getUri());
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java
index 1806414f510..85249d4e87d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/model/LbServicesProducer.java
@@ -75,7 +75,7 @@ public class LbServicesProducer implements LbServicesConfig.Producer {
serviceInfo.getServiceType().equals("qrserver")).
findAny();
if (container.isPresent()) {
- activeRotation |= Boolean.valueOf(container.get().getProperty("activeRotation").get());
+ activeRotation |= Boolean.valueOf(container.get().getProperty("activeRotation").orElse("false"));
}
}
return activeRotation;
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
index af4d998c347..48732814919 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
@@ -6,16 +6,19 @@ import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.api.HostProvisioner;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelFactory;
+import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationLockException;
+import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.OutOfCapacityException;
-import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.Rotation;
import com.yahoo.config.provision.Version;
import com.yahoo.config.provision.Zone;
import com.yahoo.lang.SettableOptional;
+import com.yahoo.log.LogLevel;
import com.yahoo.vespa.config.server.ConfigServerSpec;
import com.yahoo.vespa.config.server.deploy.ModelContextImpl;
+import com.yahoo.vespa.config.server.http.InternalServerException;
import com.yahoo.vespa.config.server.http.UnknownVespaVersionException;
import com.yahoo.vespa.config.server.provision.StaticProvisioner;
@@ -24,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
@@ -96,7 +100,12 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> {
catch (RuntimeException e) {
boolean isOldestMajor = i == majorVersions.size() - 1;
if (isOldestMajor) {
- throw new IllegalArgumentException(applicationId + ": Error loading model", e);
+ if (e instanceof NullPointerException || e instanceof NoSuchElementException) {
+ log.log(LogLevel.WARNING, "Unexpected error when building model ", e);
+ throw new InternalServerException(applicationId + ": Error loading model", e);
+ } else {
+ throw new IllegalArgumentException(applicationId + ": Error loading model", e);
+ }
} else {
log.log(Level.INFO, applicationId + ": Skipping major version " + majorVersions.get(i), e);
}
@@ -170,9 +179,10 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> {
ConfigserverConfig configserverConfig,
Zone zone,
Set<Rotation> rotations) {
- return new ModelContextImpl.Properties(applicationId,
+ return new ModelContextImpl.Properties(applicationId,
configserverConfig.multitenant(),
ConfigServerSpec.fromConfig(configserverConfig),
+ HostName.from(configserverConfig.loadBalancerAddress()),
configserverConfig.hostedVespa(),
zone,
rotations);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponses.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponses.java
index ffd86ac121e..8aaf053247e 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponses.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponses.java
@@ -76,7 +76,8 @@ public class DelayedConfigResponses {
}
public synchronized void run() {
- remove();
+ removeFromQueue();
+ removeWatcher();
rpcServer.addToRequestQueue(request, true, null);
if (log.isLoggable(LogLevel.DEBUG)) {
log.log(LogLevel.DEBUG, logPre()+"DelayedConfigResponse. putting on queue: " + request.getShortDescription());
@@ -86,9 +87,8 @@ public class DelayedConfigResponses {
/**
* Remove delayed response from its queue
*/
- private void remove() {
+ private void removeFromQueue() {
delayedResponsesQueue.remove(this);
- removeWatcher();
}
public JRTServerConfigRequest getRequest() {
@@ -107,8 +107,13 @@ public class DelayedConfigResponses {
return Tenants.logPre(app);
}
- public synchronized boolean cancel() {
- remove();
+ synchronized void cancelAndRemove() {
+ removeFromQueue();
+ cancel();
+ }
+
+ synchronized boolean cancel() {
+ removeWatcher();
if (future == null) {
throw new IllegalStateException("Cannot cancel a task that has not been scheduled");
}
@@ -129,7 +134,7 @@ public class DelayedConfigResponses {
*/
@Override
public void notifyTargetInvalid(Target target) {
- cancel();
+ cancelAndRemove();
}
private void addWatcher() {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/RpcServer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/RpcServer.java
index 3c9917bf17e..d17cdf722ea 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/RpcServer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/RpcServer.java
@@ -4,18 +4,22 @@ package com.yahoo.vespa.config.server.rpc;
import com.google.inject.Inject;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.concurrent.ThreadFactoryFactory;
+import com.yahoo.config.FileReference;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostLivenessTracker;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Version;
import com.yahoo.jrt.Acceptor;
+import com.yahoo.jrt.DataValue;
import com.yahoo.jrt.Int32Value;
+import com.yahoo.jrt.Int64Value;
import com.yahoo.jrt.ListenFailedException;
import com.yahoo.jrt.Method;
import com.yahoo.jrt.Request;
import com.yahoo.jrt.Spec;
import com.yahoo.jrt.StringValue;
import com.yahoo.jrt.Supervisor;
+import com.yahoo.jrt.Target;
import com.yahoo.jrt.Transport;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.config.ErrorCode;
@@ -27,6 +31,7 @@ import com.yahoo.vespa.config.protocol.Trace;
import com.yahoo.vespa.config.server.SuperModelRequestHandler;
import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.GetConfigContext;
+import com.yahoo.vespa.config.server.filedistribution.FileServer;
import com.yahoo.vespa.config.server.host.HostRegistries;
import com.yahoo.vespa.config.server.host.HostRegistry;
import com.yahoo.vespa.config.server.ReloadListener;
@@ -36,7 +41,10 @@ import com.yahoo.vespa.config.server.monitoring.MetricUpdaterFactory;
import com.yahoo.vespa.config.server.tenant.TenantHandlerProvider;
import com.yahoo.vespa.config.server.tenant.TenantListener;
import com.yahoo.vespa.config.server.tenant.Tenants;
+import net.jpountz.xxhash.XXHash64;
+import net.jpountz.xxhash.XXHashFactory;
+import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -68,6 +76,18 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
static final int TRACELEVEL_DEBUG = 9;
private static final String THREADPOOL_NAME = "rpcserver worker pool";
private static final long SHUTDOWN_TIMEOUT = 60;
+ private enum FileApiErrorCodes {
+ OK(0, "OK"),
+ NOT_FOUND(1, "Filereference not found");
+ private final int code;
+ private final String description;
+ FileApiErrorCodes(int code, String description) {
+ this.code = code;
+ this.description = description;
+ }
+ int getCode() { return code; }
+ String getDescription() { return description; }
+ }
private final Supervisor supervisor = new Supervisor(new Transport());
private Spec spec = null;
private final boolean useRequestVersion;
@@ -83,6 +103,7 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
private final MetricUpdater metrics;
private final MetricUpdaterFactory metricUpdaterFactory;
private final HostLivenessTracker hostLivenessTracker;
+ private final FileServer fileServer;
private final ThreadPoolExecutor executorService;
private volatile boolean allTenantsLoaded = false;
@@ -93,20 +114,23 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
* @param config The config to use for setting up this server
*/
@Inject
- public RpcServer(ConfigserverConfig config, SuperModelRequestHandler superModelRequestHandler, MetricUpdaterFactory metrics,
- HostRegistries hostRegistries, HostLivenessTracker hostLivenessTracker) {
+ public RpcServer(ConfigserverConfig config, SuperModelRequestHandler superModelRequestHandler,
+ MetricUpdaterFactory metrics, HostRegistries hostRegistries,
+ HostLivenessTracker hostLivenessTracker, FileServer fileServer) {
this.superModelRequestHandler = superModelRequestHandler;
- this.metricUpdaterFactory = metrics;
- this.supervisor.setMaxOutputBufferSize(config.maxoutputbuffersize());
+ metricUpdaterFactory = metrics;
+ supervisor.setMaxOutputBufferSize(config.maxoutputbuffersize());
this.metrics = metrics.getOrCreateMetricUpdater(Collections.<String, String>emptyMap());
this.hostLivenessTracker = hostLivenessTracker;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(config.maxgetconfigclients());
- executorService = new ThreadPoolExecutor(config.numthreads(), config.numthreads(), 0, TimeUnit.SECONDS, workQueue, ThreadFactoryFactory.getThreadFactory(THREADPOOL_NAME));
+ executorService = new ThreadPoolExecutor(config.numthreads(), config.numthreads(),
+ 0, TimeUnit.SECONDS, workQueue, ThreadFactoryFactory.getThreadFactory(THREADPOOL_NAME));
delayedConfigResponses = new DelayedConfigResponses(this, config.numDelayedResponseThreads());
spec = new Spec(null, config.rpcport());
hostRegistry = hostRegistries.getTenantHostRegistry();
this.useRequestVersion = config.useVespaVersionInRequest();
this.hostedVespa = config.hostedVespa();
+ this.fileServer = fileServer;
setUpHandlers();
}
@@ -180,6 +204,7 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
getSupervisor().addMethod(new Method("printStatistics", "", "s", this, "printStatistics")
.methodDesc("printStatistics")
.returnDesc(0, "statistics", "Statistics for server"));
+ getSupervisor().addMethod(new Method("filedistribution.serveFile", "s", "is", this, "serveFile"));
}
/**
@@ -223,7 +248,6 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
}
for (int i = 0; i < responsesSent; i++) {
-
try {
completionService.take();
} catch (InterruptedException e) {
@@ -402,4 +426,56 @@ public class RpcServer implements Runnable, ReloadListener, TenantListener {
return useRequestVersion;
}
+ class FileReceiver implements FileServer.Receiver {
+ Target target;
+ FileReceiver(Target target) {
+ this.target = target;
+ }
+
+ @Override
+ public String toString() {
+ return target.toString();
+ }
+
+ @Override
+ public void receive(FileReference reference, String filename, byte [] content, FileServer.ReplayStatus status) {
+ XXHash64 hasher = XXHashFactory.fastestInstance().hash64();
+ Request fileBlob = new Request("filedistribution.receiveFile");
+ fileBlob.parameters().add(new StringValue(reference.value()));
+ fileBlob.parameters().add(new StringValue(filename));
+ fileBlob.parameters().add(new DataValue(content));
+ fileBlob.parameters().add(new Int64Value(hasher.hash(ByteBuffer.wrap(content), 0)));
+ fileBlob.parameters().add(new Int32Value(status.getCode()));
+ fileBlob.parameters().add(new StringValue(status.getDescription()));
+ target.invokeSync(fileBlob, 600);
+ if (fileBlob.isError()) {
+ log.warning("Failed delivering reference '" + reference.value() + "' with file '" + filename + "' to " +
+ target.toString() + " with error : '" + fileBlob.errorMessage() + "'.");
+ }
+ }
+ }
+
+ @SuppressWarnings("UnusedDeclaration")
+ public final void serveFile(Request request) {
+ String fileReference = request.parameters().get(0).asString();
+ FileApiErrorCodes result;
+ try {
+ // TODO remove once verified in system tests.
+ log.info("Received request for reference '" + fileReference + "'");
+ result = fileServer.hasFile(fileReference)
+ ? FileApiErrorCodes.OK
+ : FileApiErrorCodes.NOT_FOUND;
+ if (result == FileApiErrorCodes.OK) {
+ fileServer.startFileServing(fileReference, new FileReceiver(request.target()));
+ } else {
+ fileServer.download(new FileReference(fileReference));
+ }
+ } catch (IllegalArgumentException e) {
+ result = FileApiErrorCodes.NOT_FOUND;
+ log.warning("Failed serving file reference '" + fileReference + "' with error " + e.toString());
+ }
+ request.returnValues()
+ .add(new Int32Value(result.getCode()))
+ .add(new StringValue(result.getDescription()));
+ }
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionFactory.java
index 298acaca901..e96ddb4b094 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionFactory.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionFactory.java
@@ -6,6 +6,7 @@ import com.yahoo.path.Path;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.vespa.config.server.GlobalComponentRegistry;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.config.server.zookeeper.ConfigCurator;
import com.yahoo.vespa.curator.Curator;
@@ -19,20 +20,19 @@ public class RemoteSessionFactory {
private final GlobalComponentRegistry componentRegistry;
private final Curator curator;
private final ConfigCurator configCurator;
- private final Path sessionDirPath;
+ private final Path sessionsPath;
private final ConfigDefinitionRepo defRepo;
private final TenantName tenant;
private final ConfigserverConfig configserverConfig;
private final Clock clock;
public RemoteSessionFactory(GlobalComponentRegistry componentRegistry,
- Path sessionsPath,
TenantName tenant,
Clock clock) {
this.componentRegistry = componentRegistry;
this.curator = componentRegistry.getCurator();
this.configCurator = componentRegistry.getConfigCurator();
- this.sessionDirPath = sessionsPath;
+ this.sessionsPath = Tenants.getSessionsPath(tenant);
this.tenant = tenant;
this.defRepo = componentRegistry.getConfigDefinitionRepo();
this.configserverConfig = componentRegistry.getConfigserverConfig();
@@ -40,7 +40,7 @@ public class RemoteSessionFactory {
}
public RemoteSession createSession(long sessionId) {
- Path sessionPath = sessionDirPath.append(String.valueOf(sessionId));
+ Path sessionPath = this.sessionsPath.append(String.valueOf(sessionId));
SessionZooKeeperClient sessionZKClient = new SessionZooKeeperClient(curator,
configCurator,
sessionPath,
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionRepo.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionRepo.java
index 659a44bb339..2269a7ed997 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionRepo.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSessionRepo.java
@@ -8,10 +8,12 @@ import java.util.logging.Logger;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.log.LogLevel;
import com.yahoo.path.Path;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.config.server.application.ApplicationSet;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.yolean.Exceptions;
import com.yahoo.vespa.config.server.ReloadHandler;
@@ -49,19 +51,19 @@ public class RemoteSessionRepo extends SessionRepo<RemoteSession> implements Nod
* @param curator a {@link Curator} instance.
* @param remoteSessionFactory a {@link com.yahoo.vespa.config.server.session.RemoteSessionFactory}
* @param reloadHandler a {@link com.yahoo.vespa.config.server.ReloadHandler}
- * @param sessionsPath a {@link com.yahoo.path.Path} to the sessions dir.
- * @param applicationRepo an {@link TenantApplications} object.
+ * @param tenant a {@link TenantName} instance.
+ * @param applicationRepo a {@link TenantApplications} instance.
* @param executorService an {@link ExecutorService} to run callbacks from ZooKeeper.
*/
public RemoteSessionRepo(Curator curator,
- RemoteSessionFactory remoteSessionFactory,
- ReloadHandler reloadHandler,
- Path sessionsPath,
- TenantApplications applicationRepo,
- MetricUpdater metricUpdater,
- ExecutorService executorService) {
+ RemoteSessionFactory remoteSessionFactory,
+ ReloadHandler reloadHandler,
+ TenantName tenant,
+ TenantApplications applicationRepo,
+ MetricUpdater metricUpdater,
+ ExecutorService executorService) {
this.curator = curator;
- this.sessionsPath = sessionsPath;
+ this.sessionsPath = Tenants.getSessionsPath(tenant);
this.applicationRepo = applicationRepo;
this.remoteSessionFactory = remoteSessionFactory;
this.reloadHandler = reloadHandler;
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java
index 1d5025f2e61..fdc681b5fb6 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java
@@ -16,6 +16,7 @@ import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.config.server.application.TenantApplications;
import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs;
import com.yahoo.vespa.config.server.host.HostValidator;
+import com.yahoo.vespa.config.server.tenant.Tenant;
import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.config.server.zookeeper.SessionCounter;
import com.yahoo.vespa.config.server.zookeeper.ConfigCurator;
@@ -57,7 +58,6 @@ public class SessionFactoryImpl implements SessionFactory, LocalSessionLoader {
public SessionFactoryImpl(GlobalComponentRegistry globalComponentRegistry,
SessionCounter sessionCounter,
- Path sessionsPath,
TenantApplications applicationRepo,
TenantFileSystemDirs tenantFileSystemDirs,
HostValidator<ApplicationId> hostRegistry,
@@ -68,7 +68,7 @@ public class SessionFactoryImpl implements SessionFactory, LocalSessionLoader {
this.curator = globalComponentRegistry.getCurator();
this.configCurator = globalComponentRegistry.getConfigCurator();
this.sessionCounter = sessionCounter;
- this.sessionsPath = sessionsPath;
+ this.sessionsPath = Tenants.getSessionsPath(tenant);
this.applicationRepo = applicationRepo;
this.tenantFileSystemDirs = tenantFileSystemDirs;
this.superModelGenerationCounter = globalComponentRegistry.getSuperModelGenerationCounter();
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
index 31be18d9b22..531085883c4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
@@ -9,25 +9,32 @@ import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
import com.yahoo.config.model.api.ModelContext;
-import com.yahoo.config.provision.*;
+import com.yahoo.config.provision.AllocatedHosts;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.OutOfCapacityException;
+import com.yahoo.config.provision.Rotation;
+import com.yahoo.config.provision.Version;
+import com.yahoo.config.provision.Zone;
import com.yahoo.lang.SettableOptional;
import com.yahoo.log.LogLevel;
import com.yahoo.path.Path;
-import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.ConfigServerSpec;
+import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.application.PermanentApplicationPackage;
-import com.yahoo.vespa.config.server.modelfactory.ModelFactoryRegistry;
-import com.yahoo.vespa.config.server.tenant.Rotations;
import com.yahoo.vespa.config.server.configchange.ConfigChangeActions;
import com.yahoo.vespa.config.server.deploy.ModelContextImpl;
import com.yahoo.vespa.config.server.deploy.ZooKeeperDeployer;
import com.yahoo.vespa.config.server.http.InvalidApplicationException;
+import com.yahoo.vespa.config.server.modelfactory.ModelFactoryRegistry;
import com.yahoo.vespa.config.server.modelfactory.PreparedModelsBuilder;
import com.yahoo.vespa.config.server.provision.HostProvisionerProvider;
-
+import com.yahoo.vespa.config.server.tenant.Rotations;
import com.yahoo.vespa.curator.Curator;
import org.xml.sax.SAXException;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
@@ -37,9 +44,6 @@ import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerException;
-
/**
* A SessionPreparer is responsible for preparing a session given an application package.
*
@@ -148,6 +152,7 @@ public class SessionPreparer {
this.properties = new ModelContextImpl.Properties(params.getApplicationId(),
configserverConfig.multitenant(),
ConfigServerSpec.fromConfig(configserverConfig),
+ HostName.from(configserverConfig.loadBalancerAddress()),
configserverConfig.hostedVespa(),
zone,
rotationsSet);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantBuilder.java
index 084d35a42d4..61145c2a138 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantBuilder.java
@@ -34,7 +34,6 @@ public class TenantBuilder {
private final Path tenantPath;
private final GlobalComponentRegistry componentRegistry;
private final TenantName tenant;
- private final Path sessionsPath;
private RemoteSessionRepo remoteSessionRepo;
private LocalSessionRepo localSessionRepo;
private SessionFactory sessionFactory;
@@ -47,15 +46,14 @@ public class TenantBuilder {
private TenantFileSystemDirs tenantFileSystemDirs;
private HostValidator<ApplicationId> hostValidator;
- private TenantBuilder(GlobalComponentRegistry componentRegistry, TenantName tenant, Path zkPath) {
+ private TenantBuilder(GlobalComponentRegistry componentRegistry, TenantName tenant) {
this.componentRegistry = componentRegistry;
- this.tenantPath = zkPath;
+ this.tenantPath = Tenants.getTenantPath(tenant);
this.tenant = tenant;
- this.sessionsPath = tenantPath.append(Tenant.SESSIONS);
}
- public static TenantBuilder create(GlobalComponentRegistry componentRegistry, TenantName tenant, Path zkPath) {
- return new TenantBuilder(componentRegistry, tenant, zkPath);
+ public static TenantBuilder create(GlobalComponentRegistry componentRegistry, TenantName tenant) {
+ return new TenantBuilder(componentRegistry, tenant);
}
public TenantBuilder withSessionFactory(SessionFactory sessionFactory) {
@@ -123,7 +121,7 @@ public class TenantBuilder {
private void createSessionFactory() {
if (sessionFactory == null || localSessionLoader == null) {
- SessionFactoryImpl impl = new SessionFactoryImpl(componentRegistry, sessionCounter, sessionsPath,
+ SessionFactoryImpl impl = new SessionFactoryImpl(componentRegistry, sessionCounter,
applicationRepo, tenantFileSystemDirs, hostValidator, tenant);
if (sessionFactory == null) {
sessionFactory = impl;
@@ -136,13 +134,13 @@ public class TenantBuilder {
private void createApplicationRepo() {
if (applicationRepo == null) {
- applicationRepo = ZKTenantApplications.create(componentRegistry.getCurator(), tenantPath.append(Tenant.APPLICATIONS), reloadHandler, tenant);
+ applicationRepo = ZKTenantApplications.create(componentRegistry.getCurator(), reloadHandler, tenant);
}
}
private void createSessionCounter() {
if (sessionCounter == null) {
- sessionCounter = new SessionCounter(componentRegistry.getCurator(), tenantPath, sessionsPath);
+ sessionCounter = new SessionCounter(componentRegistry.getCurator(), tenant);
}
}
@@ -167,7 +165,7 @@ public class TenantBuilder {
private void createRemoteSessionFactory(Clock clock) {
if (remoteSessionFactory == null) {
- remoteSessionFactory = new RemoteSessionFactory(componentRegistry, sessionsPath, tenant, clock);
+ remoteSessionFactory = new RemoteSessionFactory(componentRegistry, tenant, clock);
}
}
@@ -176,7 +174,7 @@ public class TenantBuilder {
remoteSessionRepo = new RemoteSessionRepo(componentRegistry.getCurator(),
remoteSessionFactory,
reloadHandler,
- sessionsPath,
+ tenant,
applicationRepo,
componentRegistry.getMetrics().getOrCreateMetricUpdater(Metrics.createDimensions(tenant)),
createSingleThreadedExecutorService(RemoteSessionRepo.class.getName()));
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/Tenants.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/Tenants.java
index 60200e34cdf..d2cf17a38d4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/Tenants.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/Tenants.java
@@ -11,7 +11,6 @@ import com.yahoo.log.LogLevel;
import com.yahoo.path.Path;
import com.yahoo.vespa.config.server.GlobalComponentRegistry;
import com.yahoo.vespa.config.server.monitoring.MetricUpdater;
-import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.curator.Curator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
@@ -78,10 +77,10 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
* @throws Exception is creating the Tenants instance fails
*/
@Inject
- public Tenants(GlobalComponentRegistry globalComponentRegistry, Metrics metrics) throws Exception {
+ public Tenants(GlobalComponentRegistry globalComponentRegistry) throws Exception {
this.globalComponentRegistry = globalComponentRegistry;
this.curator = globalComponentRegistry.getCurator();
- metricUpdater = metrics.getOrCreateMetricUpdater(Collections.emptyMap());
+ metricUpdater = globalComponentRegistry.getMetrics().getOrCreateMetricUpdater(Collections.emptyMap());
this.tenantListeners.add(globalComponentRegistry.getTenantListener());
curator.framework().getConnectionStateListenable().addListener(this);
@@ -99,15 +98,16 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
/**
* New instance containing the given tenants. This will not create Zookeeper watches. For testing only
* @param globalComponentRegistry a {@link com.yahoo.vespa.config.server.GlobalComponentRegistry} instance
- * @param metrics a {@link com.yahoo.vespa.config.server.monitoring.Metrics} instance
* @param tenants a collection of {@link Tenant}s
*/
- public Tenants(GlobalComponentRegistry globalComponentRegistry, Metrics metrics, Collection<Tenant> tenants) {
+ public Tenants(GlobalComponentRegistry globalComponentRegistry, Collection<Tenant> tenants) {
this.globalComponentRegistry = globalComponentRegistry;
this.curator = globalComponentRegistry.getCurator();
- metricUpdater = metrics.getOrCreateMetricUpdater(Collections.emptyMap());
+ metricUpdater = globalComponentRegistry.getMetrics().getOrCreateMetricUpdater(Collections.emptyMap());
this.tenantListeners.add(globalComponentRegistry.getTenantListener());
curator.create(tenantsPath);
+ createSystemTenants(globalComponentRegistry.getConfigserverConfig());
+ createTenants();
this.directoryCache = curator.createDirectoryCache(tenantsPath.getAbsolute(), false, false, pathChildrenExecutor);
this.tenants.putAll(addTenants(tenants));
}
@@ -147,7 +147,7 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
return tenants;
}
- synchronized void createTenants() throws Exception {
+ synchronized void createTenants() {
Set<TenantName> allTenants = readTenantsFromZooKeeper();
log.log(LogLevel.DEBUG, "Create tenants, tenants found in zookeeper: " + allTenants);
checkForRemovedTenants(allTenants);
@@ -159,7 +159,7 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
Map<TenantName, Tenant> current = new LinkedHashMap<>(tenants);
for (Map.Entry<TenantName, Tenant> entry : current.entrySet()) {
TenantName tenant = entry.getKey();
- if (!newTenants.contains(tenant)) {
+ if (!newTenants.contains(tenant) && !DEFAULT_TENANT.equals(tenant)) {
notifyRemovedTenant(tenant);
entry.getValue().close();
tenants.remove(tenant);
@@ -167,7 +167,7 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
}
}
- private void checkForAddedTenants(Set<TenantName> newTenants) throws Exception {
+ private void checkForAddedTenants(Set<TenantName> newTenants) {
ExecutorService executor = Executors.newFixedThreadPool(globalComponentRegistry.getConfigserverConfig().numParallelTenantLoaders());
for (TenantName tenantName : newTenants) {
// Note: the http handler will check if the tenant exists, and throw accordingly
@@ -178,12 +178,18 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
}
}
executor.shutdown();
- executor.awaitTermination(365, TimeUnit.DAYS); // Timeout should never happen
+ try {
+ executor.awaitTermination(365, TimeUnit.DAYS); // Timeout should never happen
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Executor for creating tenants did not terminate within timeout");
+ }
}
private void createTenant(TenantName tenantName) {
+ if (tenants.containsKey(tenantName)) return;
+
try {
- Tenant tenant = TenantBuilder.create(globalComponentRegistry, tenantName, getTenantPath(tenantName)).build();
+ Tenant tenant = TenantBuilder.create(globalComponentRegistry, tenantName).build();
notifyNewTenant(tenant);
tenants.put(tenantName, tenant);
} catch (Exception e) {
@@ -251,6 +257,8 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
* @return this Tenants instance
*/
public synchronized Tenants deleteTenant(TenantName name) {
+ if (name.equals(DEFAULT_TENANT))
+ throw new IllegalArgumentException("Deleting 'default' tenant is not allowed");
Tenant tenant = tenants.get(name);
tenant.delete();
return this;
@@ -267,7 +275,7 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
* @return the log string
*/
public static String logPre(ApplicationId app) {
- if (TenantName.defaultName().equals(app.tenant())) return "";
+ if (DEFAULT_TENANT.equals(app.tenant())) return "";
StringBuilder ret = new StringBuilder()
.append(logPre(app.tenant()))
.append("app:"+app.application().value())
@@ -343,6 +351,7 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
/**
* Gets zookeeper path for tenant data
+ *
* @param tenantName tenant name
* @return a {@link com.yahoo.path.Path} to the zookeeper data for a tenant
*/
@@ -350,4 +359,24 @@ public class Tenants implements ConnectionStateListener, PathChildrenCacheListen
return tenantsPath.append(tenantName.value());
}
+ /**
+ * Gets zookeeper path for session data for a tenant
+ *
+ * @param tenantName tenant name
+ * @return a {@link com.yahoo.path.Path} to the zookeeper sessions data for a tenant
+ */
+ public static Path getSessionsPath(TenantName tenantName) {
+ return getTenantPath(tenantName).append(Tenant.SESSIONS);
+ }
+
+ /**
+ * Gets zookeeper path for application data for a tenant
+ *
+ * @param tenantName tenant name
+ * @return a {@link com.yahoo.path.Path} to the zookeeper application data for a tenant
+ */
+ public static Path getApplicationsPath(TenantName tenantName) {
+ return getTenantPath(tenantName).append(Tenant.APPLICATIONS);
+ }
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/SessionCounter.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/SessionCounter.java
index 2d95a013da9..4df292dd204 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/SessionCounter.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/SessionCounter.java
@@ -1,7 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.zookeeper;
-import com.yahoo.path.Path;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.curator.Curator;
/**
@@ -12,8 +13,10 @@ import com.yahoo.vespa.curator.Curator;
*/
public class SessionCounter extends InitializedCounter {
- public SessionCounter(Curator curator, Path rootPath, Path sessionsDir) {
- super(curator, rootPath.append("sessionCounter").getAbsolute(), sessionsDir.getAbsolute());
+ public SessionCounter(Curator curator, TenantName tenantName) {
+ super(curator,
+ Tenants.getTenantPath(tenantName).append("sessionCounter").getAbsolute(),
+ Tenants.getSessionsPath(tenantName).getAbsolute());
}
/**
diff --git a/configserver/src/main/resources/configserver-app/services.xml b/configserver/src/main/resources/configserver-app/services.xml
index 7ad1b3bbbfd..fbab854ae9e 100644
--- a/configserver/src/main/resources/configserver-app/services.xml
+++ b/configserver/src/main/resources/configserver-app/services.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
<services version="1.0" xmlns:preprocess="properties">
- <preprocess:include file='controller/admin.xml' required='false' />
<jdisc id="configserver" jetty="true" version="1.0">
<config name="container.handler.threadpool">
<maxthreads>100</maxthreads> <!-- Reduced thread count to minimize memory consumption -->
</config>
<accesslog type="vespa" fileNamePattern="logs/vespa/configserver/access.log.%Y%m%d%H%M%S" rotationScheme="date" symlinkName="access.log" />
+ <preprocess:include file='access-logging.xml' required='false' />
<component id="com.yahoo.vespa.config.server.ConfigServerBootstrap" bundle="configserver" />
<component id="com.yahoo.vespa.config.server.monitoring.Metrics" bundle="configserver" />
<component id="com.yahoo.vespa.zookeeper.ZooKeeperServer" bundle="zkfacade" />
@@ -34,6 +34,7 @@
<component id="com.yahoo.config.provision.Zone" bundle="config-provisioning" />
<component id="com.yahoo.vespa.config.server.application.ApplicationConvergenceChecker" bundle="configserver" />
<component id="com.yahoo.vespa.config.server.application.HttpProxy" bundle="configserver" />
+ <component id="com.yahoo.vespa.config.server.filedistribution.FileServer" bundle="configserver" />
<component id="com.yahoo.vespa.serviceview.ConfigServerLocation" bundle="configserver" />
@@ -44,6 +45,7 @@
<preprocess:include file='config-models.xml' required='false' />
<preprocess:include file='node-repository.xml' required='false' />
<preprocess:include file='hosted-vespa/routing-status.xml' required='false' />
+ <preprocess:include file='hosted-vespa/scoreboard.xml' required='false' />
<preprocess:include file='controller/container.xml' required='false' />
<component id="com.yahoo.vespa.service.monitor.internal.SlobrokMonitorManagerImpl" bundle="service-monitor" />
<component id="com.yahoo.vespa.service.monitor.internal.ServiceMonitorImpl" bundle="service-monitor" />
diff --git a/configserver/src/main/sh/vespa-configserver-remove-state b/configserver/src/main/sh/vespa-configserver-remove-state
index 404f0f89a53..c781fcb0c0d 100755
--- a/configserver/src/main/sh/vespa-configserver-remove-state
+++ b/configserver/src/main/sh/vespa-configserver-remove-state
@@ -75,14 +75,12 @@ usage() {
sudo="sudo"
ask=true
remove_zookeeper_dir=true
-remove_applications_dir=true
remove_tenants_dir=true
confirmed=true
zookeeper_dir=var/zookeeper
-applications_dir=var/db/vespa/config_server/serverdb/applications
tenants_dir=var/db/vespa/config_server/serverdb/tenants
-if [ -w $applications_dir ] && [ -w $zookeeper_dir ]; then
+if [ -w $zookeeper_dir ]; then
sudo=""
fi
@@ -123,9 +121,8 @@ confirm() {
}
garbage_collect_dirs() {
- find $zookeeper_dir $applications_dir -type d -depth 2>/dev/null | while read dir; do
+ find $zookeeper_dir $tenants_dir -type d -depth 2>/dev/null | while read dir; do
[ "$dir" = "$zookeeper_dir" ] && continue
- [ "$dir" = "$applications_dir" ] && continue
$sudo rmdir "$dir" 2>/dev/null
done
}
@@ -148,10 +145,6 @@ if $remove_zookeeper_dir && [ -d $zookeeper_dir ]; then
confirm_and_clean_dir $zookeeper_dir
fi
-if $remove_applications_dir && [ -d $applications_dir ]; then
- confirm_and_clean_dir $applications_dir
-fi
-
if $remove_tenants_dir && [ -d $tenants_dir ]; then
confirm_and_clean_dir $tenants_dir
fi
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/InjectedGlobalComponentRegistryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/InjectedGlobalComponentRegistryTest.java
index 3efad7ac133..dec9dd991de 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/InjectedGlobalComponentRegistryTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/InjectedGlobalComponentRegistryTest.java
@@ -5,8 +5,10 @@ import com.google.common.io.Files;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.model.NullConfigModelRegistry;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.config.server.application.PermanentApplicationPackage;
+import com.yahoo.vespa.config.server.filedistribution.FileServer;
import com.yahoo.vespa.config.server.host.ConfigRequestHostLivenessTracker;
import com.yahoo.vespa.config.server.host.HostRegistries;
import com.yahoo.vespa.config.server.http.SessionHandlerTest;
@@ -61,7 +63,7 @@ public class InjectedGlobalComponentRegistryTest {
serverDB = new ConfigServerDB(configserverConfig);
sessionPreparer = new SessionTest.MockSessionPreparer();
rpcServer = new RpcServer(configserverConfig, null, Metrics.createTestMetrics(),
- new HostRegistries(), new ConfigRequestHostLivenessTracker());
+ new HostRegistries(), new ConfigRequestHostLivenessTracker(), new FileServer(FileDistribution.getDefaultFileDBPath()));
generationCounter = new SuperModelGenerationCounter(curator);
defRepo = new StaticConfigDefinitionRepo();
permanentApplicationPackage = new PermanentApplicationPackage(configserverConfig);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
index b53f82b25f3..aed0a6a9750 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java
@@ -45,6 +45,7 @@ public class ModelContextImplTest {
ApplicationId.defaultId(),
true,
Collections.emptyList(),
+ null,
false,
Zone.defaultZone(),
rotations),
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
index 1a14ac1761c..08cfa74da3b 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/TenantApplicationsTest.java
@@ -3,11 +3,11 @@ package com.yahoo.vespa.config.server.application;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.path.Path;
import com.yahoo.text.Utf8;
import com.yahoo.vespa.config.server.MockReloadHandler;
import com.yahoo.vespa.config.server.TestWithCurator;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import org.junit.Test;
import java.util.Arrays;
@@ -18,60 +18,61 @@ import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
/**
- * @author lulf
+ * @author Ulf Lilleengen
* @since 5.1
*/
public class TenantApplicationsTest extends TestWithCurator {
+ private static final TenantName tenantName = TenantName.from("tenant");
+
@Test
public void require_that_applications_are_read_from_zookeeper() throws Exception {
- curatorFramework.create().creatingParentsIfNeeded().forPath("/foo:dev:baz", Utf8.toAsciiBytes(3));
- curatorFramework.create().creatingParentsIfNeeded().forPath("/bar:test:bim", Utf8.toAsciiBytes(4));
+ writeApplicationData(createApplicationId("foo"), 3L);
+ writeApplicationData(createApplicationId("bar"), 4L);
TenantApplications repo = createZKAppRepo();
List<ApplicationId> applications = repo.listApplications();
assertThat(applications.size(), is(2));
- assertThat(applications.get(0).application().value(), is("dev"));
- assertThat(applications.get(1).application().value(), is("test"));
+ assertThat(applications.get(0).application().value(), is("foo"));
+ assertThat(applications.get(1).application().value(), is("bar"));
assertThat(repo.getSessionIdForApplication(applications.get(0)), is(3L));
assertThat(repo.getSessionIdForApplication(applications.get(1)), is(4L));
}
@Test
public void require_that_invalid_entries_are_skipped() throws Exception {
- curatorFramework.create().creatingParentsIfNeeded().forPath("/foo:dev:baz");
- curatorFramework.create().creatingParentsIfNeeded().forPath("/invalid");
+ writeApplicationData(createApplicationId("foo"), 3L);
+ writeApplicationData("invalid", 3L);
TenantApplications repo = createZKAppRepo();
List<ApplicationId> applications = repo.listApplications();
assertThat(applications.size(), is(1));
- assertThat(applications.get(0).application().value(), is("dev"));
+ assertThat(applications.get(0).application().value(), is("foo"));
}
@Test(expected = IllegalArgumentException.class)
public void require_that_requesting_session_for_unknown_application_throws_exception() throws Exception {
- curatorFramework.create().creatingParentsIfNeeded().forPath("/foo:dev:baz:bim");
TenantApplications repo = createZKAppRepo();
- repo.getSessionIdForApplication(new ApplicationId.Builder()
- .tenant("exist")
- .applicationName("tenant").instanceName("here").build());
+ repo.getSessionIdForApplication(createApplicationId("nonexistent"));
}
@Test(expected = IllegalArgumentException.class)
public void require_that_requesting_session_for_empty_application_throws_exception() throws Exception {
- curatorFramework.create().creatingParentsIfNeeded().forPath("/foo:dev:baz:bim");
+ ApplicationId baz = createApplicationId("baz");
+ // No data in node
+ curatorFramework.create().creatingParentsIfNeeded()
+ .forPath(Tenants.getApplicationsPath(tenantName).append(baz.serializedForm()).getAbsolute());
TenantApplications repo = createZKAppRepo();
- repo.getSessionIdForApplication(new ApplicationId.Builder()
- .tenant("tenant")
- .applicationName("foo").instanceName("bim").build());
+ repo.getSessionIdForApplication(baz);
}
@Test
public void require_that_application_ids_can_be_written() throws Exception {
TenantApplications repo = createZKAppRepo();
- repo.createPutApplicationTransaction(createAppplicationId("myapp"), 3l).commit();
- String path = "/mytenant:myapp:myinst";
+ ApplicationId myapp = createApplicationId("myapp");
+ repo.createPutApplicationTransaction(myapp, 3l).commit();
+ String path = Tenants.getApplicationsPath(tenantName).append(myapp.serializedForm()).getAbsolute();
assertTrue(curatorFramework.checkExists().forPath(path) != null);
assertThat(Utf8.toString(curatorFramework.getData().forPath(path)), is("3"));
- repo.createPutApplicationTransaction(createAppplicationId("myapp"), 5l).commit();
+ repo.createPutApplicationTransaction(myapp, 5l).commit();
assertTrue(curatorFramework.checkExists().forPath(path) != null);
assertThat(Utf8.toString(curatorFramework.getData().forPath(path)), is("5"));
}
@@ -79,8 +80,8 @@ public class TenantApplicationsTest extends TestWithCurator {
@Test
public void require_that_application_ids_can_be_deleted() throws Exception {
TenantApplications repo = createZKAppRepo();
- ApplicationId id1 = createAppplicationId("myapp");
- ApplicationId id2 = createAppplicationId("myapp2");
+ ApplicationId id1 = createApplicationId("myapp");
+ ApplicationId id2 = createApplicationId("myapp2");
repo.createPutApplicationTransaction(id1, 1).commit();
repo.createPutApplicationTransaction(id2, 1).commit();
assertThat(repo.listApplications().size(), is(2));
@@ -95,8 +96,8 @@ public class TenantApplicationsTest extends TestWithCurator {
TenantApplications zkRepo = createZKAppRepo();
TenantApplications memRepo = new MemoryTenantApplications();
for (TenantApplications repo : Arrays.asList(zkRepo, memRepo)) {
- ApplicationId id1 = createAppplicationId("myapp");
- ApplicationId id2 = createAppplicationId("myapp2");
+ ApplicationId id1 = createApplicationId("myapp");
+ ApplicationId id2 = createApplicationId("myapp2");
repo.createPutApplicationTransaction(id1, 4).commit();
repo.createPutApplicationTransaction(id2, 5).commit();
List<ApplicationId> lst = repo.listApplications();
@@ -122,21 +123,19 @@ public class TenantApplicationsTest extends TestWithCurator {
@Test
public void require_that_reload_handler_is_called_when_apps_are_removed() throws Exception {
- curatorFramework.create().creatingParentsIfNeeded().forPath("/foo:test:baz", Utf8.toAsciiBytes(3));
- curatorFramework.create().creatingParentsIfNeeded().forPath("/bar:dev:bim", Utf8.toAsciiBytes(4));
+ ApplicationId foo = createApplicationId("foo");
+ writeApplicationData(foo, 3L);
+ writeApplicationData(createApplicationId("bar"), 4L);
MockReloadHandler reloadHandler = new MockReloadHandler();
TenantApplications repo = createZKAppRepo(reloadHandler);
assertNull(reloadHandler.lastRemoved);
- repo.deleteApplication(new ApplicationId.Builder()
- .tenant("foo")
- .applicationName("test").instanceName("baz").build())
- .commit();
+ repo.deleteApplication(foo).commit();
long endTime = System.currentTimeMillis() + 60_000;
while (System.currentTimeMillis() < endTime && reloadHandler.lastRemoved == null) {
Thread.sleep(100);
}
assertNotNull(reloadHandler.lastRemoved);
- assertThat(reloadHandler.lastRemoved.serializedForm(), is("foo:test:baz"));
+ assertThat(reloadHandler.lastRemoved.serializedForm(), is(foo.serializedForm()));
}
private TenantApplications createZKAppRepo() {
@@ -144,12 +143,26 @@ public class TenantApplicationsTest extends TestWithCurator {
}
private TenantApplications createZKAppRepo(MockReloadHandler reloadHandler) {
- return ZKTenantApplications.create(curator, Path.createRoot(), reloadHandler, TenantName.from("mytenant"));
+ return ZKTenantApplications.create(curator, reloadHandler, tenantName);
}
- private static ApplicationId createAppplicationId(String name) {
+ private static ApplicationId createApplicationId(String name) {
return new ApplicationId.Builder()
- .tenant("mytenant")
- .applicationName(name).instanceName("myinst").build();
+ .tenant(tenantName.value())
+ .applicationName(name)
+ .instanceName("myinst")
+ .build();
+ }
+
+ private void writeApplicationData(ApplicationId applicationId, long sessionId) throws Exception {
+ writeApplicationData(applicationId.serializedForm(), sessionId);
+ }
+
+ private void writeApplicationData(String applicationId, long sessionId) throws Exception {
+ curatorFramework
+ .create()
+ .creatingParentsIfNeeded()
+ .forPath(Tenants.getApplicationsPath(tenantName).append(applicationId).getAbsolute(),
+ Utf8.toAsciiBytes(sessionId));
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
index 64932700173..d9a0db7e811 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java
@@ -69,26 +69,19 @@ public class DeployTester {
}
public DeployTester(String appPath, List<ModelFactory> modelFactories) {
- this(appPath, modelFactories, new ConfigserverConfig(new ConfigserverConfig.Builder()
- .configServerDBDir(Files.createTempDir()
- .getAbsolutePath())
- .configDefinitionsDir(Files.createTempDir()
- .getAbsolutePath())),
+ this(appPath, modelFactories,
+ new ConfigserverConfig(new ConfigserverConfig.Builder()
+ .configServerDBDir(Files.createTempDir().getAbsolutePath())
+ .configDefinitionsDir(Files.createTempDir().getAbsolutePath())),
Clock.systemUTC());
}
public DeployTester(String appPath, ConfigserverConfig configserverConfig) {
- this(appPath,
- Collections.singletonList(createModelFactory(Clock.systemUTC())),
- configserverConfig,
- Clock.systemUTC());
+ this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC());
}
public DeployTester(String appPath, ConfigserverConfig configserverConfig, Clock clock) {
- this(appPath,
- Collections.singletonList(createModelFactory(clock)),
- configserverConfig,
- clock);
+ this(appPath, Collections.singletonList(createModelFactory(clock)), configserverConfig, clock);
}
public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig) {
@@ -96,24 +89,22 @@ public class DeployTester {
}
public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock) {
- Metrics metrics = Metrics.createTestMetrics();
- Curator curator = new MockCurator();
this.clock = clock;
- TestComponentRegistry componentRegistry = createComponentRegistry(curator, metrics, modelFactories,
- configserverConfig, clock);
+ TestComponentRegistry componentRegistry = createComponentRegistry(new MockCurator(), Metrics.createTestMetrics(),
+ modelFactories, configserverConfig, clock);
try {
this.testApp = new File(appPath);
- this.tenants = new Tenants(componentRegistry, metrics);
+ this.tenants = new Tenants(componentRegistry, Collections.emptySet());
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
- applicationRepository = new ApplicationRepository(tenants,
- createHostProvisioner(),
- clock);
+ applicationRepository = new ApplicationRepository(tenants, createHostProvisioner(), clock);
}
- public Tenant tenant() { return tenants.defaultTenant(); }
+ public Tenant tenant() {
+ return tenants.defaultTenant();
+ }
/** Create a model factory for the version of this source*/
public static ModelFactory createModelFactory(Clock clock) {
@@ -139,6 +130,7 @@ public class DeployTester {
* Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet.
*/
public ApplicationId deployApp(String appName, String vespaVersion, Instant now) {
+
Tenant tenant = tenant();
LocalSession session = tenant.getSessionFactory().createSession(testApp, appName, new TimeoutBudget(clock, Duration.ofSeconds(60)));
ApplicationId id = ApplicationId.from(tenant.getName(), ApplicationName.from(appName), InstanceName.defaultName());
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/filedistribution/FileServerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/filedistribution/FileServerTest.java
new file mode 100644
index 00000000000..09260987ac0
--- /dev/null
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/filedistribution/FileServerTest.java
@@ -0,0 +1,112 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.filedistribution;
+
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.FileReference;
+import com.yahoo.io.IOUtils;
+import com.yahoo.net.HostName;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class FileServerTest {
+
+ FileServer fs = new FileServer(new File("."));
+ List<File> created = new LinkedList<>();
+
+ private void createCleanDir(String name) throws IOException{
+ File dir = new File(name);
+ IOUtils.recursiveDeleteDir(dir);
+ IOUtils.createDirectory(dir.getName());
+ File dummy = new File(dir.getName() +"/dummy");
+ IOUtils.writeFile(dummy, "test", true);
+ assertTrue(dummy.delete());
+ created.add(dir);
+ }
+
+ @Test
+ public void requireThatExistingFileCanbeFound() throws IOException {
+ createCleanDir("123");
+ IOUtils.writeFile("123/f1", "test", true);
+ assertTrue(fs.hasFile("123"));
+ cleanup();
+ }
+
+ @Test
+ public void requireThatNonExistingFileCanNotBeFound() throws IOException {
+ assertFalse(fs.hasFile("12x"));
+ createCleanDir("12x");
+ assertFalse(fs.hasFile("12x"));
+ cleanup();
+ }
+
+ private static class FileReceiver implements FileServer.Receiver {
+ CompletableFuture<byte []> content;
+ FileReceiver(CompletableFuture<byte []> content) {
+ this.content = content;
+ }
+ @Override
+ public void receive(FileReference reference, String filename, byte[] content, FileServer.ReplayStatus status) {
+ this.content.complete(content);
+ }
+ }
+
+ @Test
+ public void requireThatWeCanReplayFile() throws IOException, InterruptedException, ExecutionException {
+ createCleanDir("12y");
+ IOUtils.writeFile("12y/f1", "dummy-data", true);
+ CompletableFuture<byte []> content = new CompletableFuture<>();
+ fs.startFileServing("12y", new FileReceiver(content));
+ assertEquals(new String(content.get()), "dummy-data");
+ cleanup();
+ }
+
+ @Test
+ public void requireThatDifferentNumberOfConfigServersWork() throws IOException {
+ // Empty connection pool in tests etc.
+ ConfigserverConfig.Builder builder = new ConfigserverConfig.Builder();
+ FileServer fileServer = new FileServer(new ConfigserverConfig(builder));
+ assertEquals(0, fileServer.downloader().fileReferenceDownloader().connectionPool().getSize());
+
+ // Empty connection pool when only one server, no use in downloading from yourself
+ List<ConfigserverConfig.Zookeeperserver.Builder> servers = new ArrayList<>();
+ ConfigserverConfig.Zookeeperserver.Builder serverBuilder = new ConfigserverConfig.Zookeeperserver.Builder();
+ serverBuilder.hostname(HostName.getLocalhost());
+ serverBuilder.port(123456);
+ servers.add(serverBuilder);
+ builder.zookeeperserver(servers);
+ fileServer = new FileServer(new ConfigserverConfig(builder));
+ assertEquals(0, fileServer.downloader().fileReferenceDownloader().connectionPool().getSize());
+
+ // connection pool of size 1 when 2 servers
+ ConfigserverConfig.Zookeeperserver.Builder serverBuilder2 = new ConfigserverConfig.Zookeeperserver.Builder();
+ serverBuilder2.hostname("bar");
+ serverBuilder2.port(123456);
+ servers.add(serverBuilder2);
+ builder.zookeeperserver(servers);
+ fileServer = new FileServer(new ConfigserverConfig(builder));
+ assertEquals(1, fileServer.downloader().fileReferenceDownloader().connectionPool().getSize());
+ }
+
+ private void cleanup() {
+ created.forEach((file) -> IOUtils.recursiveDeleteDir(file));
+ created.clear();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ cleanup();
+ }
+
+}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/CompressedApplicationInputStreamTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/CompressedApplicationInputStreamTest.java
index 5d23f1a4556..ddd29f96695 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/CompressedApplicationInputStreamTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/CompressedApplicationInputStreamTest.java
@@ -1,8 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http;
+import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
-import com.yahoo.vespa.config.server.http.CompressedApplicationInputStream;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
@@ -10,16 +10,19 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.junit.Test;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
/**
* @author lulf
@@ -37,6 +40,7 @@ public class CompressedApplicationInputStreamTest {
File app = new File("src/test/resources/deploy/validapp");
writeFileToTar(taos, new File(app, "services.xml"));
writeFileToTar(taos, new File(app, "hosts.xml"));
+ writeFileToTar(taos, new File(app, "deployment.xml"));
taos.close();
return outFile;
}
@@ -55,14 +59,8 @@ public class CompressedApplicationInputStreamTest {
void assertTestApp(File outApp) {
String [] files = outApp.list();
- assertThat(files.length, is(2));
- if ("hosts.xml".equals(files[0])) {
- assertThat(files[1], is("services.xml"));
- } else if ("hosts.xml".equals(files[1])) {
- assertThat(files[0], is("services.xml"));
- } else {
- fail("Both services.xml and hosts.xml should be contained in the unpacked application");
- }
+ assertThat(files.length, is(3));
+ assertThat(Arrays.asList(files), containsInAnyOrder(ImmutableList.of(is("hosts.xml"), is("services.xml"), is("deployment.xml"))));
}
@Test
@@ -88,6 +86,10 @@ public class CompressedApplicationInputStreamTest {
archiveOutputStream.putArchiveEntry(archiveOutputStream.createArchiveEntry(file, "application/" + file.getName()));
ByteStreams.copy(new FileInputStream(file), archiveOutputStream);
archiveOutputStream.closeArchiveEntry();
+ file = new File(app, "deployment.xml");
+ archiveOutputStream.putArchiveEntry(archiveOutputStream.createArchiveEntry(file, "application/" + file.getName()));
+ ByteStreams.copy(new FileInputStream(file), archiveOutputStream);
+ archiveOutputStream.closeArchiveEntry();
archiveOutputStream.close();
@@ -134,9 +136,10 @@ public class CompressedApplicationInputStreamTest {
new TarArchiveInputStream(new GZIPInputStream(new FileInputStream(gzFile))));
File outApp = unpacked.decompress();
List<File> files = Arrays.asList(outApp.listFiles());
- assertThat(files.size(), is(4));
+ assertThat(files.size(), is(5));
assertTrue(files.contains(new File(outApp, "services.xml")));
assertTrue(files.contains(new File(outApp, "hosts.xml")));
+ assertTrue(files.contains(new File(outApp, "deployment.xml")));
assertTrue(files.contains(new File(outApp, "searchdefinitions")));
assertTrue(files.contains(new File(outApp, "external")));
File sd = files.get(files.indexOf(new File(outApp, "searchdefinitions")));
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
index 892c821950e..5552758a0a6 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
@@ -292,7 +292,7 @@ public class ApplicationHandlerTest {
Collections.singletonList(new VespaModelFactory(new NullConfigModelRegistry()))))
.build();
- Tenants tenants = new Tenants(componentRegistry, Metrics.createTestMetrics()); // Creates the application path element in zk
+ Tenants tenants = new Tenants(componentRegistry); // Creates the application path element in zk
tenants.addTenant(tenantName);
Tenant tenant = tenants.getTenant(tenantName);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionActiveHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionActiveHandlerTest.java
index 6b25772f85d..9d04b7e982d 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionActiveHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionActiveHandlerTest.java
@@ -19,10 +19,8 @@ import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.HttpRequest;
-import com.yahoo.path.Path;
import com.yahoo.slime.JsonFormat;
import com.yahoo.vespa.config.server.ApplicationRepository;
-import com.yahoo.vespa.config.server.PathProvider;
import com.yahoo.vespa.config.server.SuperModelGenerationCounter;
import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.application.MemoryTenantApplications;
@@ -45,6 +43,7 @@ import com.yahoo.vespa.config.server.session.SessionContext;
import com.yahoo.vespa.config.server.session.SessionFactory;
import com.yahoo.vespa.config.server.session.SessionTest;
import com.yahoo.vespa.config.server.session.SessionZooKeeperClient;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.config.server.zookeeper.ConfigCurator;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
@@ -83,7 +82,6 @@ public class SessionActiveHandlerTest extends SessionHandlerTest {
private Curator curator;
private RemoteSessionRepo remoteSessionRepo;
private LocalSessionRepo localRepo;
- private PathProvider pathProvider;
private TenantApplications applicationRepo;
private MockProvisioner hostProvisioner;
@@ -95,7 +93,6 @@ public class SessionActiveHandlerTest extends SessionHandlerTest {
configCurator = ConfigCurator.create(curator);
localRepo = new LocalSessionRepo(Clock.systemUTC());
pathPrefix = "/application/v2/tenant/" + tenant + "/session/";
- pathProvider = new PathProvider(Path.createRoot());
hostProvisioner = new MockProvisioner();
}
@@ -213,7 +210,7 @@ public class SessionActiveHandlerTest extends SessionHandlerTest {
private RemoteSession createRemoteSession(long sessionId, Session.Status status, SessionZooKeeperClient zkClient, Clock clock) throws IOException {
zkClient.writeStatus(status);
- ZooKeeperClient zkC = new ZooKeeperClient(configCurator, new BaseDeployLogger(), false, pathProvider.getSessionDirs().append(String.valueOf(sessionId)));
+ ZooKeeperClient zkC = new ZooKeeperClient(configCurator, new BaseDeployLogger(), false, Tenants.getSessionsPath(tenant).append(String.valueOf(sessionId)));
VespaModelFactory modelFactory = new VespaModelFactory(new NullConfigModelRegistry());
zkC.write(Collections.singletonMap(modelFactory.getVersion(), new MockFileRegistry()));
zkC.write(AllocatedHosts.withHosts(Collections.emptySet()));
@@ -318,7 +315,7 @@ public class SessionActiveHandlerTest extends SessionHandlerTest {
}
ActivateRequest invoke(boolean createLocalSession) throws Exception {
- SessionZooKeeperClient zkClient = new MockSessionZKClient(curator, pathProvider.getSessionDirs().append(String.valueOf(sessionId)),
+ SessionZooKeeperClient zkClient = new MockSessionZKClient(curator, tenant, sessionId,
Optional.of(AllocatedHosts.withHosts(Collections.singleton(new HostSpec("bar", Collections.emptyList())))));
session = createRemoteSession(sessionId, initialStatus, zkClient, clock);
if (createLocalSession) {
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
index 7fe7b350734..310342e81f1 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
@@ -3,11 +3,11 @@ package com.yahoo.vespa.config.server.http.v2;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.logging.AccessLog;
-import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.application.MemoryTenantApplications;
import com.yahoo.vespa.config.server.application.TenantApplications;
@@ -15,24 +15,33 @@ import com.yahoo.vespa.config.server.http.CompressedApplicationInputStreamTest;
import com.yahoo.vespa.config.server.http.HandlerTest;
import com.yahoo.vespa.config.server.http.HttpErrorResponse;
import com.yahoo.vespa.config.server.http.SessionHandlerTest;
-import com.yahoo.vespa.config.server.session.*;
+import com.yahoo.vespa.config.server.session.LocalSessionRepo;
+import com.yahoo.vespa.config.server.session.SessionFactory;
import com.yahoo.vespa.config.server.tenant.Tenants;
-import com.yahoo.vespa.curator.mock.MockCurator;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
import java.time.Clock;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import static com.yahoo.jdisc.Response.Status.*;
+import static com.yahoo.jdisc.Response.Status.BAD_REQUEST;
+import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
+import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED;
+import static com.yahoo.jdisc.Response.Status.OK;
+import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
+import static com.yahoo.jdisc.http.HttpRequest.Method.POST;
import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.*;
-
-import static com.yahoo.jdisc.http.HttpRequest.Method.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* @author hmusum
@@ -168,7 +177,7 @@ public class SessionCreateHandlerTest extends SessionHandlerTest {
assertTrue(applicationPackage.exists());
final File[] files = applicationPackage.listFiles();
assertNotNull(files);
- assertThat(files.length, is(2));
+ assertThat(files.length, is(3));
}
@Test
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java
index 428cd16508f..7900a67bddd 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java
@@ -20,7 +20,6 @@ import com.yahoo.slime.JsonDecoder;
import com.yahoo.slime.Slime;
import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.config.server.ApplicationRepository;
-import com.yahoo.vespa.config.server.PathProvider;
import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.host.HostRegistry;
@@ -33,6 +32,7 @@ import com.yahoo.vespa.config.server.http.*;
import com.yahoo.vespa.config.server.session.*;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
+import org.apache.commons.lang.NullArgumentException;
import org.junit.Before;
import org.junit.Test;
@@ -149,14 +149,13 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest {
*/
private RemoteSessionRepo fromLocalSessionRepo(LocalSessionRepo localRepo, Clock clock) {
RemoteSessionRepo remoteRepo = new RemoteSessionRepo();
- PathProvider pathProvider = new PathProvider(Path.createRoot());
for (LocalSession ls : localRepo.listSessions()) {
- zooKeeperClient = new MockSessionZKClient(curator, pathProvider.getSessionDirs().append(String.valueOf(ls.getSessionId())));
+ zooKeeperClient = new MockSessionZKClient(curator, tenant, ls.getSessionId());
if (ls.getStatus()!=null) zooKeeperClient.writeStatus(ls.getStatus());
- RemoteSession remSess = new RemoteSession(TenantName.from("default"), ls.getSessionId(),
+ RemoteSession remSess = new RemoteSession(tenant, ls.getSessionId(),
new TestComponentRegistry.Builder().curator(curator).build(),
- zooKeeperClient,
+ zooKeeperClient,
clock);
remoteRepo.addSession(remSess);
}
@@ -239,8 +238,8 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest {
public void require_that_preparing_with_multiple_tenants_work() throws Exception {
// Need different repos for 'default' tenant as opposed to the 'test' tenant
LocalSessionRepo localRepoDefault = new LocalSessionRepo(Clock.systemUTC());
- final TenantName tenantName = TenantName.defaultName();
- addTenant(tenantName, localRepoDefault, new RemoteSessionRepo(), new MockSessionFactory());
+ final TenantName defaultTenant = TenantName.defaultName();
+ addTenant(defaultTenant, localRepoDefault, new RemoteSessionRepo(), new MockSessionFactory());
addTestTenant();
final SessionHandler handler = createHandler(builder);
@@ -248,7 +247,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest {
// Deploy with default tenant
MockSession session = new MockSession(sessionId, null);
localRepoDefault.addSession(session);
- pathPrefix = "/application/v2/tenant/default/session/";
+ pathPrefix = "/application/v2/tenant/" + defaultTenant + "/session/";
HttpResponse response = handler.handle(
SessionHandlerTest.createTestRequest(pathPrefix, HttpRequest.Method.PUT, Cmd.PREPARED, sessionId));
@@ -317,7 +316,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest {
@Test
public void test_out_of_capacity_response() throws InterruptedException, IOException {
- String message = "No nodes available";
+ String message = "Internal error";
SessionThrowingException session = new SessionThrowingException(new OutOfCapacityException(message));
localRepo.addSession(session);
HttpResponse response = createHandler()
@@ -329,6 +328,19 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest {
}
@Test
+ public void test_that_nullpointerexception_gives_internal_server_error() throws InterruptedException, IOException {
+ String message = "No nodes available";
+ SessionThrowingException session = new SessionThrowingException(new NullPointerException(message));
+ localRepo.addSession(session);
+ HttpResponse response = createHandler()
+ .handle(SessionHandlerTest.createTestRequest(pathPrefix, HttpRequest.Method.PUT, Cmd.PREPARED, 1L));
+ assertEquals(500, response.getStatus());
+ Slime data = getData(response);
+ assertThat(data.get().field("error-code").asString(), is(HttpErrorResponse.errorCodes.INTERNAL_SERVER_ERROR.name()));
+ assertThat(data.get().field("message").asString(), is(message));
+ }
+
+ @Test
public void test_application_lock_failure() throws InterruptedException, IOException {
String message = "Timed out after waiting PT1M to acquire lock '/provision/v1/locks/foo/bar/default'";
SessionThrowingException session =
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TenantTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TenantTest.java
index d82f62cfc1a..9dbb193ab3d 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TenantTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TenantTest.java
@@ -9,7 +9,6 @@ import java.util.concurrent.Executor;
import com.yahoo.vespa.config.server.*;
import com.yahoo.vespa.config.server.http.SessionResponse;
-import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.config.server.tenant.Tenants;
import org.junit.After;
import org.junit.Before;
@@ -35,7 +34,7 @@ public class TenantTest extends TestWithCurator {
}
protected Tenants createTenants() throws Exception {
- return new Tenants(new TestComponentRegistry.Builder().curator(curator).build(), Metrics.createTestMetrics());
+ return new Tenants(new TestComponentRegistry.Builder().curator(curator).build());
}
protected Executor testExecutor() {
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TestTenantBuilder.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TestTenantBuilder.java
index 2b1000c2211..16ce605d4d1 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TestTenantBuilder.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/TestTenantBuilder.java
@@ -4,10 +4,9 @@ package com.yahoo.vespa.config.server.http.v2;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.path.Path;
-import com.yahoo.vespa.config.server.*;
+import com.yahoo.vespa.config.server.GlobalComponentRegistry;
+import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.application.MemoryTenantApplications;
-import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.config.server.session.LocalSessionRepo;
import com.yahoo.vespa.config.server.session.RemoteSessionRepo;
import com.yahoo.vespa.config.server.tenant.Tenant;
@@ -19,7 +18,7 @@ import java.util.*;
/**
* Test utility for creating tenants used for testing and setup wiring of tenant stuff.
*
- * @author lulf
+ * @author Ulf Lilleengen
* @since 5.1
*/
public class TestTenantBuilder {
@@ -33,7 +32,7 @@ public class TestTenantBuilder {
public TenantBuilder createTenant(TenantName tenantName) {
MemoryTenantApplications applicationRepo = new MemoryTenantApplications();
- TenantBuilder builder = TenantBuilder.create(componentRegistry, tenantName, Path.createRoot().append(tenantName.value()))
+ TenantBuilder builder = TenantBuilder.create(componentRegistry, tenantName)
.withSessionFactory(new SessionCreateHandlerTest.MockSessionFactory())
.withLocalSessionRepo(new LocalSessionRepo(componentRegistry.getClock()))
.withRemoteSessionRepo(new RemoteSessionRepo())
@@ -57,6 +56,6 @@ public class TestTenantBuilder {
}
}
});
- return new Tenants(componentRegistry, Metrics.createTestMetrics(), tenantList);
+ return new Tenants(componentRegistry, tenantList);
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java
index 474b93f6972..df8ed405fe3 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/model/LbServicesProducerTest.java
@@ -88,8 +88,9 @@ public class LbServicesProducerTest {
private LbServicesConfig createModelAndGetLbServicesConfig(RegionName regionName) throws IOException, SAXException {
final Zone zone = new Zone(Environment.prod, regionName);
- Map<TenantName, Map<ApplicationId, ApplicationInfo>> testModel = createTestModel(new DeployState.Builder().
- properties(new DeployProperties.Builder().zone(zone).build()));
+ Map<TenantName, Map<ApplicationId, ApplicationInfo>> testModel = createTestModel(new DeployState.Builder()
+ .properties(new DeployProperties.Builder().zone(zone).build())
+ .zone(zone));
return getLbServicesConfig(new Zone(Environment.prod, regionName), testModel);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponseTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponseTest.java
index 122deadb841..0126a9e2f29 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponseTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/DelayedConfigResponseTest.java
@@ -12,8 +12,6 @@ import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
import com.yahoo.vespa.config.protocol.JRTServerConfigRequestV3;
import com.yahoo.vespa.config.protocol.Trace;
import com.yahoo.vespa.config.server.GetConfigContext;
-import com.yahoo.vespa.config.server.rpc.DelayedConfigResponses;
-import com.yahoo.vespa.config.server.rpc.MockRpc;
import org.junit.Test;
import java.util.Collections;
@@ -58,7 +56,7 @@ public class DelayedConfigResponseTest {
DelayedConfigResponses responses = new DelayedConfigResponses(rpc, 1, false);
responses.delayResponse(createRequest("foolio", "md5", "myid", "mymd5", 3, 100000, "bar"), context);
assertThat(responses.size(), is(1));
- responses.allDelayedResponses().get(0).cancel();
+ responses.allDelayedResponses().get(0).cancelAndRemove();
assertThat(responses.size(), is(0));
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpc.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpc.java
index a08514e8afb..4c2a4b56751 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpc.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpc.java
@@ -2,11 +2,13 @@
package com.yahoo.vespa.config.server.rpc;
import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Version;
import com.yahoo.vespa.config.protocol.ConfigResponse;
import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
import com.yahoo.vespa.config.server.GetConfigContext;
+import com.yahoo.vespa.config.server.filedistribution.FileServer;
import com.yahoo.vespa.config.server.host.ConfigRequestHostLivenessTracker;
import com.yahoo.vespa.config.server.host.HostRegistries;
import com.yahoo.vespa.config.server.monitoring.Metrics;
@@ -37,7 +39,7 @@ public class MockRpc extends RpcServer {
public MockRpc(int port, boolean createDefaultTenant, boolean pretendToHaveLoadedAnyApplication) {
super(createConfig(port), null, Metrics.createTestMetrics(),
- new HostRegistries(), new ConfigRequestHostLivenessTracker());
+ new HostRegistries(), new ConfigRequestHostLivenessTracker(), new FileServer(FileDistribution.getDefaultFileDBPath()));
if (createDefaultTenant) {
onTenantCreate(TenantName.from("default"), new MockTenantProvider(pretendToHaveLoadedAnyApplication));
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/TestWithRpc.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/TestWithRpc.java
index fa6adb64a8a..12dc584f055 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/TestWithRpc.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/TestWithRpc.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.config.server.rpc;
import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.provision.HostLivenessTracker;
import com.yahoo.config.provision.TenantName;
import com.yahoo.jrt.Request;
@@ -12,6 +13,7 @@ import com.yahoo.net.HostName;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.config.GenerationCounter;
import com.yahoo.vespa.config.server.*;
+import com.yahoo.vespa.config.server.filedistribution.FileServer;
import com.yahoo.vespa.config.server.host.ConfigRequestHostLivenessTracker;
import com.yahoo.vespa.config.server.host.HostRegistries;
import com.yahoo.vespa.config.server.monitoring.Metrics;
@@ -88,7 +90,7 @@ public class TestWithRpc {
emptyNodeFlavors(),
generationCounter)),
Metrics.createTestMetrics(), new HostRegistries(),
- hostLivenessTracker);
+ hostLivenessTracker, new FileServer(FileDistribution.getDefaultFileDBPath()));
rpcServer.onTenantCreate(TenantName.from("default"), tenantProvider);
t = new Thread(rpcServer);
t.start();
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionRepoTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionRepoTest.java
index 5753b2959f7..3d34d08edeb 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionRepoTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionRepoTest.java
@@ -2,10 +2,11 @@
package com.yahoo.vespa.config.server.session;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
-import com.yahoo.path.Path;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.config.server.*;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.config.server.GlobalComponentRegistry;
+import com.yahoo.vespa.config.server.TestComponentRegistry;
+import com.yahoo.vespa.config.server.TestWithCurator;
import com.yahoo.vespa.config.server.application.MemoryTenantApplications;
import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs;
import com.yahoo.io.IOUtils;
@@ -20,13 +21,12 @@ import java.io.File;
import java.time.Duration;
import java.time.Instant;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
- * @author lulf
+ * @author Ulf Lilleengen
* @since 5.1
*/
public class LocalSessionRepoTest extends TestWithCurator {
@@ -51,10 +51,7 @@ public class LocalSessionRepoTest extends TestWithCurator {
}
clock = new ManualClock(Instant.ofEpochSecond(1));
LocalSessionLoader loader = new SessionFactoryImpl(globalComponentRegistry,
- new SessionCounter(globalComponentRegistry.getCurator(),
- Path.fromString("counter"),
- Path.fromString("sessions")),
- Path.createRoot(),
+ new SessionCounter(globalComponentRegistry.getCurator(), tenantName),
new MemoryTenantApplications(),
tenantFileSystemDirs, new HostRegistry<>(),
tenantName);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
index c6099e724bc..b98fa49ac26 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
@@ -13,6 +13,7 @@ import com.yahoo.vespa.config.server.deploy.DeployHandlerLogger;
import com.yahoo.vespa.config.server.deploy.TenantFileSystemDirs;
import com.yahoo.vespa.config.server.deploy.ZooKeeperClient;
import com.yahoo.vespa.config.server.host.HostRegistry;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.config.server.zookeeper.ConfigCurator;
@@ -108,13 +109,15 @@ public class LocalSessionTest {
@Test
public void require_that_session_can_be_deleted() throws Exception {
- LocalSession session = createSession(TenantName.defaultName(), 3);
- assertTrue(configCurator.exists("/3"));
+ TenantName tenantName = TenantName.defaultName();
+ LocalSession session = createSession(tenantName, 3);
+ String sessionNode = Tenants.getSessionsPath(tenantName).append(String.valueOf(3)).getAbsolute();
+ assertTrue(configCurator.exists(sessionNode));
assertTrue(new File(tenantFileSystemDirs.sessionsPath(), "3").exists());
long gen = superModelGenerationCounter.get();
session.delete();
assertThat(superModelGenerationCounter.get(), is(gen + 1));
- assertFalse(configCurator.exists("/3"));
+ assertFalse(configCurator.exists(sessionNode));
assertFalse(new File(tenantFileSystemDirs.sessionsPath(), "3").exists());
}
@@ -155,10 +158,9 @@ public class LocalSessionTest {
}
private LocalSession createSession(TenantName tenant, long sessionId, SessionTest.MockSessionPreparer preparer, Optional<AllocatedHosts> allocatedHosts) throws Exception {
- Path sessionPath = Path.fromString("/" + sessionId);
- SessionZooKeeperClient zkc = new MockSessionZKClient(curator, sessionPath, allocatedHosts);
+ SessionZooKeeperClient zkc = new MockSessionZKClient(curator, tenant, sessionId, allocatedHosts);
zkc.createWriteStatusTransaction(Session.Status.NEW).commit();
- ZooKeeperClient zkClient = new ZooKeeperClient(configCurator, new BaseDeployLogger(), false, sessionPath);
+ ZooKeeperClient zkClient = new ZooKeeperClient(configCurator, new BaseDeployLogger(), false, Tenants.getSessionsPath(tenant).append(String.valueOf(sessionId)));
if (allocatedHosts.isPresent()) {
zkClient.write(allocatedHosts.get());
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/MockSessionZKClient.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/MockSessionZKClient.java
index 62b0ecbada2..a4331216334 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/MockSessionZKClient.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/MockSessionZKClient.java
@@ -4,8 +4,10 @@ package com.yahoo.vespa.config.server.session;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.provision.AllocatedHosts;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.transaction.Transaction;
import com.yahoo.path.Path;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
@@ -22,17 +24,17 @@ public class MockSessionZKClient extends SessionZooKeeperClient {
private Optional<AllocatedHosts> info = Optional.empty();
private Session.Status sessionStatus;
- public MockSessionZKClient(Curator curator, Path sessionPath) {
- this(curator, sessionPath, (ApplicationPackage)null);
+ public MockSessionZKClient(Curator curator, TenantName tenantName, long sessionId) {
+ this(curator, tenantName, sessionId, (ApplicationPackage)null);
}
- public MockSessionZKClient(Curator curator, Path sessionPath, Optional<AllocatedHosts> allocatedHosts) {
- this(curator, sessionPath);
+ public MockSessionZKClient(Curator curator, TenantName tenantName, long sessionId, Optional<AllocatedHosts> allocatedHosts) {
+ this(curator, tenantName, sessionId);
this.info = allocatedHosts;
}
- public MockSessionZKClient(Curator curator, Path sessionPath, ApplicationPackage application) {
- super(curator, sessionPath);
+ public MockSessionZKClient(Curator curator, TenantName tenantName, long sessionId, ApplicationPackage application) {
+ super(curator, Tenants.getSessionsPath(tenantName).append(String.valueOf(sessionId)));
this.app = application;
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java
index 462062ce8a8..878339bd703 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java
@@ -2,18 +2,22 @@
package com.yahoo.vespa.config.server.session;
import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.path.Path;
import com.yahoo.text.Utf8;
import com.yahoo.transaction.Transaction;
-import com.yahoo.vespa.config.server.*;
+import com.yahoo.vespa.config.server.TestComponentRegistry;
+import com.yahoo.vespa.config.server.TestWithCurator;
import com.yahoo.vespa.config.server.application.TenantApplications;
import com.yahoo.vespa.config.server.tenant.Tenant;
import com.yahoo.vespa.config.server.tenant.TenantBuilder;
+import com.yahoo.vespa.config.server.tenant.Tenants;
import com.yahoo.vespa.curator.Curator;
import org.junit.Before;
import org.junit.Test;
@@ -27,33 +31,35 @@ import java.util.concurrent.TimeUnit;
import java.util.function.LongPredicate;
/**
- * @author lulf
+ * @author Ulf Lilleengen
* @since 5.1
*/
public class RemoteSessionRepoTest extends TestWithCurator {
+ private static final TenantName tenantName = TenantName.defaultName();
+
private RemoteSessionRepo remoteSessionRepo;
@Before
public void setupFacade() throws Exception {
- createSession(2l, false);
- createSession(3l, false);
- curator.create(Path.fromString("/applications"));
- curator.create(Path.fromString("/sessions"));
- Tenant tenant = TenantBuilder.create(new TestComponentRegistry.Builder().curator(curator).build(),
- TenantName.defaultName(),
- Path.createRoot()).build();
+ Tenant tenant = TenantBuilder.create(new TestComponentRegistry.Builder()
+ .curator(curator)
+ .build(),
+ tenantName)
+ .build();
this.remoteSessionRepo = tenant.getRemoteSessionRepo();
+ curator.create(Tenants.getTenantPath(tenantName).append("/applications"));
+ curator.create(Tenants.getSessionsPath(tenantName));
+ createSession(1l, false);
+ createSession(2l, false);
}
private void createSession(long sessionId, boolean wait) {
- createSession("", sessionId, wait);
+ createSession(sessionId, wait, tenantName);
}
-
- private void createSession(String root, long sessionId, boolean wait) {
- Path sessionsPath = Path.fromString(root).append("sessions");
- curator.create(sessionsPath);
+ private void createSession(long sessionId, boolean wait, TenantName tenantName) {
+ Path sessionsPath = Tenants.getSessionsPath(tenantName);
SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, sessionsPath.append(String.valueOf(sessionId)));
zkc.createNewSession(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
if (wait) {
@@ -64,27 +70,28 @@ public class RemoteSessionRepoTest extends TestWithCurator {
@Test
public void testInitialize() {
+ assertSessionExists(1l);
assertSessionExists(2l);
- assertSessionExists(3l);
}
@Test
public void testCreateSession() throws Exception {
- createSession(0l, true);
- assertSessionExists(0l);
+ createSession(3l, true);
+ assertSessionExists(3l);
}
@Test
public void testSessionStateChange() throws Exception {
- Path session = Path.fromString("/sessions/0");
- createSession(0l, true);
- assertSessionStatus(0l, Session.Status.NEW);
- assertStatusChange(0l, Session.Status.PREPARE);
- assertStatusChange(0l, Session.Status.ACTIVATE);
+ long sessionId = 3L;
+ createSession(sessionId, true);
+ assertSessionStatus(sessionId, Session.Status.NEW);
+ assertStatusChange(sessionId, Session.Status.PREPARE);
+ assertStatusChange(sessionId, Session.Status.ACTIVATE);
+ Path session = Tenants.getSessionsPath(tenantName).append("" + sessionId);
curator.delete(session);
- assertSessionRemoved(0l);
- assertNull(remoteSessionRepo.getSession(0l));
+ assertSessionRemoved(sessionId);
+ assertNull(remoteSessionRepo.getSession(sessionId));
}
// If reading a session throws an exception it should be handled and not prevent other applications
@@ -93,25 +100,25 @@ public class RemoteSessionRepoTest extends TestWithCurator {
// throw an exception).
@Test
public void testBadApplicationRepoOnActivate() throws Exception {
+ long sessionId = 3L;
TenantApplications applicationRepo = new FailingTenantApplications();
- curator.framework().create().forPath("/mytenant");
- Tenant tenant = TenantBuilder.create(new TestComponentRegistry.Builder().curator(curator).build(),
- TenantName.from("mytenant"),
- Path.fromString("mytenant"))
+ TenantName mytenant = TenantName.from("mytenant");
+ Tenant tenant = TenantBuilder.create(new TestComponentRegistry.Builder().curator(curator).build(), mytenant)
.withApplicationRepo(applicationRepo)
.build();
+ curator.create(Tenants.getSessionsPath(mytenant));
remoteSessionRepo = tenant.getRemoteSessionRepo();
assertThat(remoteSessionRepo.listSessions().size(), is(0));
- createSession("/mytenant", 2l, true);
+ createSession(sessionId, true, mytenant);
assertThat(remoteSessionRepo.listSessions().size(), is(1));
}
private void assertStatusChange(long sessionId, Session.Status status) throws Exception {
- Path statePath = Path.fromString("/sessions/" + sessionId).append(ConfigCurator.SESSIONSTATE_ZK_SUBPATH);
+ Path statePath = Tenants.getSessionsPath(tenantName).append("" + sessionId).append(ConfigCurator.SESSIONSTATE_ZK_SUBPATH);
curator.create(statePath);
curatorFramework.setData().forPath(statePath.getAbsolute(), Utf8.toBytes(status.toString()));
System.out.println("Setting status " + status + " for " + sessionId);
- assertSessionStatus(0l, status);
+ assertSessionStatus(sessionId, status);
}
private void assertSessionRemoved(long sessionId) {
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionTest.java
index 44f304847ba..9598a9262f0 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionTest.java
@@ -11,10 +11,8 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.provision.Version;
-import com.yahoo.path.Path;
import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.modelfactory.ModelFactoryRegistry;
-import com.yahoo.vespa.config.server.PathProvider;
import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.application.PermanentApplicationPackage;
import com.yahoo.vespa.curator.mock.MockCurator;
@@ -49,13 +47,13 @@ import static org.junit.Assert.assertTrue;
*/
public class RemoteSessionTest {
+ private static final TenantName tenantName = TenantName.from("default");
+
private Curator curator;
- private PathProvider pathProvider;
@Before
public void setupTest() throws Exception {
curator = new MockCurator();
- pathProvider = new PathProvider(Path.createRoot());
}
@Test
@@ -180,7 +178,7 @@ public class RemoteSessionTest {
okFactory.vespaVersion = Version.fromIntValues(2, 0, 0);
okFactory.throwOnLoad = false;
- SessionZooKeeperClient zkc = new MockSessionZKClient(curator, pathProvider.getSessionDir(3), application);
+ SessionZooKeeperClient zkc = new MockSessionZKClient(curator, tenantName, 3, application);
RemoteSession session = createSession(3, zkc, Arrays.asList(okFactory, failingFactory), failingFactory.clock());
session.loadPrepared();
@@ -189,7 +187,7 @@ public class RemoteSessionTest {
@Test
public void require_that_session_status_is_updated() throws IOException, SAXException {
- SessionZooKeeperClient zkc = new MockSessionZKClient(curator, pathProvider.getSessionDir(3));
+ SessionZooKeeperClient zkc = new MockSessionZKClient(curator, tenantName, 3);
RemoteSession session = createSession(3, zkc, Clock.systemUTC());
assertThat(session.getStatus(), is(Session.Status.NEW));
zkc.writeStatus(Session.Status.PREPARE);
@@ -203,7 +201,7 @@ public class RemoteSessionTest {
MockModelFactory mockModelFactory = new MockModelFactory();
try {
int sessionId = 3;
- SessionZooKeeperClient zkc = new MockSessionZKClient(curator, pathProvider.getSessionDir(sessionId));
+ SessionZooKeeperClient zkc = new MockSessionZKClient(curator, tenantName, sessionId);
createSession(sessionId, zkc, Collections.singletonList(mockModelFactory), permanentApp, mockModelFactory.clock()).ensureApplicationLoaded();
} catch (Exception e) {
e.printStackTrace();
@@ -220,7 +218,7 @@ public class RemoteSessionTest {
return createSession(sessionId, zkc, Collections.singletonList(new VespaModelFactory(new NullConfigModelRegistry())), clock);
}
private RemoteSession createSession(long sessionId, List<ModelFactory> modelFactories, Clock clock) {
- SessionZooKeeperClient zkc = new MockSessionZKClient(curator, pathProvider.getSessionDir(sessionId));
+ SessionZooKeeperClient zkc = new MockSessionZKClient(curator, tenantName, sessionId);
return createSession(sessionId, zkc, modelFactories, clock);
}
@@ -238,7 +236,8 @@ public class RemoteSessionTest {
if (permanentApplicationPackage.isPresent())
registryBuilder.permanentApplicationPackage(permanentApplicationPackage.get());
- return new RemoteSession(TenantName.from("default"), sessionId,
+
+ return new RemoteSession(tenantName, sessionId,
registryBuilder.build(),
zkc,
clock);
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java
index 5dc529e3381..2069ae48d76 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java
@@ -126,7 +126,6 @@ public class SessionPreparerTest extends TestWithCurator {
new PrepareParams.Builder().dryRun(true).timeoutBudget(TimeoutBudgetTest.day()).build(),
Optional.empty(), tenantPath, Instant.now());
assertThat(fileDistributionFactory.mockFileDistributionProvider.getMockFileDBHandler().sendDeployedFilesCalled, is(0));
- assertThat(fileDistributionFactory.mockFileDistributionProvider.getMockFileDBHandler().limitSendingOfDeployedFilesToCalled, is(0));
assertThat(fileDistributionFactory.mockFileDistributionProvider.getMockFileDBHandler().reloadDeployFileDistributorCalled, is(0));
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionRepoTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionRepoTest.java
index 1bb25bc37db..01cb90721f3 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionRepoTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionRepoTest.java
@@ -1,8 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.session;
-import com.yahoo.path.Path;
-import com.yahoo.vespa.config.server.PathProvider;
import com.yahoo.vespa.curator.mock.MockCurator;
import org.junit.Test;
@@ -34,10 +32,10 @@ public class SessionRepoTest {
}
private class TestSession extends Session {
- public TestSession(long sessionId) {
- super(TenantName.from("default"),
+ TestSession(long sessionId) {
+ super(TenantName.defaultName(),
sessionId,
- new MockSessionZKClient(new MockCurator(), new PathProvider(Path.createRoot()).getSessionDir(sessionId)));
+ new MockSessionZKClient(new MockCurator(), TenantName.defaultName(), sessionId));
}
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandlerTest.java
index 91cf6e79165..dc6268c5a25 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantRequestHandlerTest.java
@@ -11,7 +11,6 @@ import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.Version;
import com.yahoo.io.IOUtils;
-import com.yahoo.path.Path;
import com.yahoo.vespa.config.ConfigKey;
import com.yahoo.vespa.config.ConfigPayload;
import com.yahoo.vespa.config.GetConfigRequest;
@@ -20,7 +19,6 @@ import com.yahoo.vespa.config.protocol.DefContent;
import com.yahoo.vespa.config.protocol.VespaVersion;
import com.yahoo.vespa.config.server.application.ApplicationSet;
import com.yahoo.vespa.config.server.host.HostRegistries;
-import com.yahoo.vespa.config.server.PathProvider;
import com.yahoo.vespa.config.server.ReloadListener;
import com.yahoo.vespa.config.server.ServerCache;
import com.yahoo.vespa.config.server.TestComponentRegistry;
@@ -88,7 +86,7 @@ public class TenantRequestHandlerTest extends TestWithCurator {
private void feedApp(File appDir, long sessionId, ApplicationId appId) throws IOException {
SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, configCurator,
- new PathProvider(Path.createRoot()).getSessionDir(sessionId),
+ Tenants.getSessionsPath(tenant).append(String.valueOf(sessionId)),
new TestConfigDefinitionRepo(),
"", Optional.empty());
zkc.writeApplicationId(appId);
@@ -104,7 +102,7 @@ public class TenantRequestHandlerTest extends TestWithCurator {
private ApplicationSet reloadConfig(long id, String application, Clock clock) {
SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, configCurator,
- new PathProvider(Path.createRoot()).getSessionDir(id),
+ Tenants.getSessionsPath(tenant).append(String.valueOf(id)),
new TestConfigDefinitionRepo(),
"", Optional.empty());
zkc.writeApplicationId(new ApplicationId.Builder().tenant(tenant).applicationName(application).build());
@@ -187,7 +185,7 @@ public class TenantRequestHandlerTest extends TestWithCurator {
public void testResolveForAppId() {
long id = 1l;
SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, configCurator,
- new PathProvider(Path.createRoot()).getSessionDir(id),
+ Tenants.getSessionsPath(tenant).append(String.valueOf(id)),
new TestConfigDefinitionRepo(),
"", Optional.empty());
ApplicationId appId = new ApplicationId.Builder()
@@ -231,7 +229,7 @@ public class TenantRequestHandlerTest extends TestWithCurator {
private void feedAndReloadApp(File appDir, long sessionId, ApplicationId appId) throws IOException {
feedApp(appDir, sessionId, appId);
- SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, new PathProvider(Path.createRoot()).getSessionDir(sessionId));
+ SessionZooKeeperClient zkc = new SessionZooKeeperClient(curator, Tenants.getSessionsPath(tenant).append(String.valueOf(sessionId)));
zkc.writeApplicationId(appId);
RemoteSession session = new RemoteSession(tenant, sessionId, componentRegistry, zkc, Clock.systemUTC());
server.reloadConfig(session.ensureApplicationLoaded());
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantsTestCase.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantsTestCase.java
index d1724986d5e..e650997b7e0 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantsTestCase.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TenantsTestCase.java
@@ -11,7 +11,6 @@ import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.TestWithCurator;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.vespa.config.server.monitoring.MetricUpdater;
-import com.yahoo.vespa.config.server.monitoring.Metrics;
import com.yahoo.vespa.model.VespaModel;
import org.junit.After;
import org.junit.Before;
@@ -20,6 +19,7 @@ import org.xml.sax.SAXException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -46,7 +46,7 @@ public class TenantsTestCase extends TestWithCurator {
listener = (TenantRequestHandlerTest.MockReloadListener)globalComponentRegistry.getReloadListener();
tenantListener = (MockTenantListener)globalComponentRegistry.getTenantListener();
tenantListener.tenantsLoaded = false;
- tenants = new Tenants(globalComponentRegistry, Metrics.createTestMetrics());
+ tenants = new Tenants(globalComponentRegistry);
assertTrue(tenantListener.tenantsLoaded);
tenants.addTenant(tenant1);
tenants.addTenant(tenant2);
@@ -105,19 +105,28 @@ public class TenantsTestCase extends TestWithCurator {
}
@Test
- public void testRemove() throws Exception {
+ public void testDelete() throws Exception {
assertNotNull(globalComponentRegistry.getCurator().framework().checkExists().forPath(tenants.tenantZkPath(tenant1)));
tenants.deleteTenant(tenant1);
assertFalse(tenants.getAllTenantNames().contains(tenant1));
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testDeleteOfDefaultTenant() {
+ try {
+ assertNotNull(globalComponentRegistry.getCurator().framework().checkExists().forPath(tenants.tenantZkPath(TenantName.defaultName())));
+ } catch (Exception e) {
+ fail("default tenant does not exist");
+ }
+ tenants.deleteTenant(TenantName.defaultName());
+ }
@Test
public void testTenantsChanged() throws Exception {
tenants.close(); // close the Tenants instance created in setupSession, we do not want to use one with a PatchChildrenCache listener
- tenants = new Tenants(globalComponentRegistry, Metrics.createTestMetrics(), new ArrayList<>());
+ tenants = new Tenants(globalComponentRegistry, new ArrayList<>());
TenantName defaultTenant = TenantName.defaultName();
tenants.addTenant(tenant2);
- tenants.addTenant(defaultTenant);
tenants.createTenants();
Set<TenantName> allTenants = tenants.getAllTenantNames();
assertTrue(allTenants.contains(tenant2));
@@ -125,12 +134,10 @@ public class TenantsTestCase extends TestWithCurator {
assertTrue(allTenants.contains(defaultTenant));
tenants.deleteTenant(tenant1);
tenants.deleteTenant(tenant2);
- tenants.deleteTenant(defaultTenant);
tenants.createTenants();
allTenants = tenants.getAllTenantNames();
assertFalse(allTenants.contains(tenant1));
assertFalse(allTenants.contains(tenant2));
- assertFalse(allTenants.contains(defaultTenant));
TenantName foo = TenantName.from("foo");
TenantName bar = TenantName.from("bar");
tenants.addTenant(tenant2);
@@ -145,25 +152,24 @@ public class TenantsTestCase extends TestWithCurator {
@Test
public void testTenantWatching() throws Exception {
- TestComponentRegistry reg = new TestComponentRegistry.Builder().curator(curator).build();
- Tenants t = new Tenants(reg, Metrics.createTestMetrics());
+ TenantName newTenant = TenantName.from("newTenant");
+ List<TenantName> expectedTenants = Arrays.asList(TenantName.defaultName(), newTenant);
try {
- assertTrue(t.getAllTenantNames().contains(TenantName.defaultName()));
- reg.getCurator().framework().create().forPath(tenants.tenantZkPath(TenantName.from("newTenant")));
+ tenants.addTenant(newTenant);
// Poll for the watcher to pick up the tenant from zk, and add it
int tries=0;
while(true) {
- if (tries > 500) fail("Didn't react on watch");
- if (t.getAllTenantNames().contains(TenantName.from("newTenant"))) {
- return;
+ if (tries > 5000) fail("Didn't react on watch");
+ if (tenants.getAllTenantNames().containsAll(expectedTenants)) {
+ break;
}
tries++;
- Thread.sleep(100);
+ Thread.sleep(10);
}
} finally {
- t.close();
+ assertTrue(tenants.getAllTenantNames().containsAll(expectedTenants));
+ tenants.close();
}
}
-
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TestWithTenant.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TestWithTenant.java
index c11480f5335..4573f785842 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TestWithTenant.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/TestWithTenant.java
@@ -3,7 +3,6 @@ package com.yahoo.vespa.config.server.tenant;
import com.yahoo.vespa.config.server.TestComponentRegistry;
import com.yahoo.vespa.config.server.TestWithCurator;
-import com.yahoo.vespa.config.server.monitoring.Metrics;
import org.junit.Before;
/**
@@ -19,8 +18,7 @@ public class TestWithTenant extends TestWithCurator {
@Before
public void setupTenant() throws Exception {
- final Metrics metrics = Metrics.createTestMetrics();
- tenants = new Tenants(new TestComponentRegistry.Builder().curator(curator).metrics(metrics).build(), metrics);
+ tenants = new Tenants(new TestComponentRegistry.Builder().curator(curator).build());
tenant = tenants.defaultTenant();
}
diff --git a/configserver/src/test/resources/deploy/advancedapp/deployment.xml b/configserver/src/test/resources/deploy/advancedapp/deployment.xml
new file mode 100644
index 00000000000..fa1d1388e67
--- /dev/null
+++ b/configserver/src/test/resources/deploy/advancedapp/deployment.xml
@@ -0,0 +1 @@
+<deployment version='1.0'/> \ No newline at end of file
diff --git a/configserver/src/test/resources/deploy/app/deployment.xml b/configserver/src/test/resources/deploy/app/deployment.xml
new file mode 100644
index 00000000000..fa1d1388e67
--- /dev/null
+++ b/configserver/src/test/resources/deploy/app/deployment.xml
@@ -0,0 +1 @@
+<deployment version='1.0'/> \ No newline at end of file
diff --git a/configserver/src/test/resources/deploy/validapp/deployment.xml b/configserver/src/test/resources/deploy/validapp/deployment.xml
new file mode 100644
index 00000000000..fa1d1388e67
--- /dev/null
+++ b/configserver/src/test/resources/deploy/validapp/deployment.xml
@@ -0,0 +1 @@
+<deployment version='1.0'/> \ No newline at end of file