aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@yahooinc.com>2023-02-24 14:46:55 +0100
committerValerij Fredriksen <valerijf@yahooinc.com>2023-02-24 14:46:55 +0100
commit99d8d804a7e478900585fc60244b6cfbb999c3db (patch)
tree74496b0c552d22c7d8c2973d31f8e6f4af453654 /node-repository
parent1af61047e6009df087dee4e6d2e0f16ac0e7dd55 (diff)
Use ArchiveUris in ArchiveUriManager
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManager.java88
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializer.java56
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java13
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializer.java45
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ArchiveResponse.java20
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManagerTest.java69
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializerTest.java29
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializerTest.java27
8 files changed, 183 insertions, 164 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManager.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManager.java
index 722fd0bac56..27488e4027c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManager.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManager.java
@@ -1,94 +1,88 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.archive;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Zone;
import com.yahoo.lang.CachedSupplier;
import com.yahoo.vespa.curator.Lock;
import com.yahoo.vespa.hosted.provision.Node;
-import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.persistence.CuratorDb;
import java.time.Duration;
-import java.util.Map;
import java.util.Optional;
-import java.util.TreeMap;
-import java.util.logging.Level;
+import java.util.function.Function;
import java.util.logging.Logger;
-import java.util.regex.Pattern;
/**
- * Thread safe class to get and set archive URI for given tenants. Archive URIs are stored in ZooKeeper so that
- * nodes within the same tenant have the same archive URI from all the config servers.
+ * Thread safe class to get and set archive URI for given account and tenants.
*
* @author freva
*/
public class ArchiveUriManager {
private static final Logger log = Logger.getLogger(ArchiveUriManager.class.getName());
- private static final Pattern validUriPattern = Pattern.compile("[a-z0-9]+://(?:(?:[a-z0-9]+(?:[-_][a-z0-9.]+)*)+/)+");
private static final Duration cacheTtl = Duration.ofMinutes(1);
private final CuratorDb db;
- private final CachedSupplier<Map<TenantName, String>> archiveUris;
private final Zone zone;
+ private final CachedSupplier<ArchiveUris> archiveUris;
public ArchiveUriManager(CuratorDb db, Zone zone) {
this.db = db;
- this.archiveUris = new CachedSupplier<>(db::readArchiveUris, cacheTtl);
this.zone = zone;
+ this.archiveUris = new CachedSupplier<>(db::readArchiveUris, cacheTtl);
}
- /** Returns the current archive URI for each tenant */
- public Map<TenantName, String> getArchiveUris() {
+ public ArchiveUris archiveUris() {
return archiveUris.get();
}
- /** Returns the archive URI to use for given tenant */
- private Optional<String> archiveUriFor(TenantName tenant) {
- return Optional.ofNullable(archiveUris.get().get(tenant));
- }
-
/** Returns the archive URI to use for given node */
public Optional<String> archiveUriFor(Node node) {
- if (node.cloudAccount().isEnclave(zone)) return Optional.empty(); // TODO (freva): Implement for exclave
-
- return node.allocation().map(Allocation::owner)
- .flatMap(app -> archiveUriFor(app.tenant())
- .map(uri -> {
- StringBuilder sb = new StringBuilder(100).append(uri)
- .append(app.application().value()).append('/')
- .append(app.instance().value()).append('/')
- .append(node.allocation().get().membership().cluster().id().value()).append('/');
-
- for (char c: node.hostname().toCharArray()) {
- if (c == '.') break;
- sb.append(c);
- }
-
- return sb.append('/').toString();
- }));
+ if (node.allocation().isEmpty()) return Optional.empty();
+ ApplicationId app = node.allocation().get().owner();
+
+ return Optional.ofNullable(node.cloudAccount().isEnclave(zone) ?
+ archiveUris.get().accountArchiveUris().get(node.cloudAccount()) :
+ archiveUris.get().tenantArchiveUris().get(app.tenant()))
+ .map(uri -> {
+ StringBuilder sb = new StringBuilder(100).append(uri)
+ .append(app.application().value()).append('/')
+ .append(app.instance().value()).append('/')
+ .append(node.allocation().get().membership().cluster().id().value()).append('/');
+
+ for (char c: node.hostname().toCharArray()) {
+ if (c == '.') break;
+ sb.append(c);
+ }
+
+ return sb.append('/').toString();
+ });
}
/** Set (or remove, if archiveURI is empty) archive URI to use for given tenant */
public void setArchiveUri(TenantName tenant, Optional<String> archiveUri) {
+ setArchiveUri(au -> au.with(tenant, archiveUri));
+ }
+
+ /** Set (or remove, if archiveURI is empty) archive URI to use for given account */
+ public void setArchiveUri(CloudAccount account, Optional<String> archiveUri) {
+ if (!account.isEnclave(zone) || account.isUnspecified())
+ throw new IllegalArgumentException("Cannot set archive URI for non-enclave account: " + account);
+ setArchiveUri(au -> au.with(account, archiveUri));
+ }
+
+ private void setArchiveUri(Function<ArchiveUris, ArchiveUris> mapper) {
try (Lock lock = db.lockArchiveUris()) {
- Map<TenantName, String> archiveUris = new TreeMap<>(db.readArchiveUris());
- if (Optional.ofNullable(archiveUris.get(tenant)).equals(archiveUri)) return; // No change
+ ArchiveUris archiveUris = db.readArchiveUris();
+ ArchiveUris updated = mapper.apply(archiveUris);
+ if (archiveUris.equals(updated)) return; // No change
- archiveUri.map(ArchiveUriManager::normalizeUri).ifPresentOrElse(uri -> archiveUris.put(tenant, uri),
- () -> archiveUris.remove(tenant));
- db.writeArchiveUris(archiveUris);
+ db.writeArchiveUris(updated);
this.archiveUris.invalidate(); // Throw away current cache
- log.log(Level.FINE, () -> archiveUri.map(s -> "Set archive URI for " + tenant + " to " + s)
- .orElseGet(() -> "Remove archive URI for " + tenant));
}
}
- static String normalizeUri(String uri) {
- if (!uri.endsWith("/")) uri = uri + "/";
- if (!validUriPattern.matcher(uri).matches())
- throw new IllegalArgumentException("Invalid archive URI: " + uri);
- return uri;
- }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializer.java
new file mode 100644
index 00000000000..3bf37816dd4
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializer.java
@@ -0,0 +1,56 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.persistence;
+
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.ObjectTraverser;
+import com.yahoo.slime.Slime;
+import com.yahoo.slime.SlimeUtils;
+import com.yahoo.vespa.hosted.provision.archive.ArchiveUris;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Serializer for archive URIs that are set per tenant and per account.
+ *
+ * @author freva
+ */
+public class ArchiveUriSerializer {
+
+ private ArchiveUriSerializer() {}
+
+ public static byte[] toJson(ArchiveUris archiveUris) {
+ Slime slime = new Slime();
+ Cursor root = slime.setObject();
+
+ Cursor tenantObject = root.setObject("tenant");
+ archiveUris.tenantArchiveUris().forEach((tenant, uri) -> tenantObject.setString(tenant.value(), uri));
+
+ Cursor accountObject = root.setObject("account");
+ archiveUris.accountArchiveUris().forEach((account, uri) -> accountObject.setString(account.value(), uri));
+
+ try {
+ return SlimeUtils.toJsonBytes(slime);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static ArchiveUris fromJson(byte[] data) {
+ Inspector inspector = SlimeUtils.jsonToSlime(data).get();
+
+ Map<TenantName, String> tenantArchiveUris = new HashMap<>();
+ inspector.field("tenant").traverse((ObjectTraverser) (key, value) -> tenantArchiveUris.put(TenantName.from(key), value.asString()));
+
+ Map<CloudAccount, String> accountArchiveUris = new HashMap<>();
+ inspector.field("account").traverse((ObjectTraverser) (key, value) -> accountArchiveUris.put(CloudAccount.from(key), value.asString()));
+
+ return new ArchiveUris(tenantArchiveUris, accountArchiveUris);
+ }
+
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
index c25dfe9f1e2..5aea6858f60 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDb.java
@@ -10,7 +10,6 @@ import com.yahoo.config.provision.ApplicationTransaction;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.TenantName;
import com.yahoo.path.Path;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.transaction.Transaction;
@@ -21,6 +20,7 @@ import com.yahoo.vespa.curator.transaction.CuratorOperations;
import com.yahoo.vespa.curator.transaction.CuratorTransaction;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.applications.Application;
+import com.yahoo.vespa.hosted.provision.archive.ArchiveUris;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerId;
import com.yahoo.vespa.hosted.provision.node.Agent;
@@ -70,7 +70,7 @@ public class CuratorDb {
private static final Path infrastructureVersionsPath = root.append("infrastructureVersions");
private static final Path osVersionsPath = root.append("osVersions");
private static final Path firmwareCheckPath = root.append("firmwareCheck");
- private static final Path archiveUrisPath = root.append("archiveUris");
+ private static final Path archiveUrisPath = root.append("archiveUri");
private static final Duration defaultLockTimeout = Duration.ofMinutes(1);
@@ -102,6 +102,7 @@ public class CuratorDb {
db.create(archiveUrisPath);
db.create(loadBalancersPath);
provisionIndexCounter.initialize(100);
+ CuratorOperations.delete(root.append("archiveUris").toString()); // TODO (freva): March 2023
}
/** Adds a set of nodes. Rollbacks/fails transaction if any node is not in the expected state. */
@@ -375,16 +376,16 @@ public class CuratorDb {
// Archive URIs -----------------------------------------------------------
- public void writeArchiveUris(Map<TenantName, String> archiveUris) {
- byte[] data = TenantArchiveUriSerializer.toJson(archiveUris);
+ public void writeArchiveUris(ArchiveUris archiveUris) {
+ byte[] data = ArchiveUriSerializer.toJson(archiveUris);
NestedTransaction transaction = new NestedTransaction();
CuratorTransaction curatorTransaction = db.newCuratorTransactionIn(transaction);
curatorTransaction.add(CuratorOperations.setData(archiveUrisPath.getAbsolute(), data));
transaction.commit();
}
- public Map<TenantName, String> readArchiveUris() {
- return read(archiveUrisPath, TenantArchiveUriSerializer::fromJson).orElseGet(Map::of);
+ public ArchiveUris readArchiveUris() {
+ return read(archiveUrisPath, ArchiveUriSerializer::fromJson).orElseGet(() -> new ArchiveUris(Map.of(), Map.of()));
}
public Lock lockArchiveUris() {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializer.java
deleted file mode 100644
index d381d25704a..00000000000
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.provision.persistence;
-
-import com.yahoo.config.provision.TenantName;
-import com.yahoo.slime.Cursor;
-import com.yahoo.slime.Inspector;
-import com.yahoo.slime.ObjectTraverser;
-import com.yahoo.slime.Slime;
-import com.yahoo.slime.SlimeUtils;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Serializer for archive URIs that are set per tenant.
- *
- * @author freva
- */
-public class TenantArchiveUriSerializer {
-
- private TenantArchiveUriSerializer() {}
-
- public static byte[] toJson(Map<TenantName, String> archiveUrisByTenantName) {
- Slime slime = new Slime();
- Cursor object = slime.setObject();
- archiveUrisByTenantName.forEach((tenantName, archiveUri) ->
- object.setString(tenantName.value(), archiveUri));
- try {
- return SlimeUtils.toJsonBytes(slime);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static Map<TenantName, String> fromJson(byte[] data) {
- Map<TenantName, String> archiveUrisByTenantName = new TreeMap<>(); // Use TreeMap to sort by tenant name
- Inspector inspector = SlimeUtils.jsonToSlime(data).get();
- inspector.traverse((ObjectTraverser) (key, value) ->
- archiveUrisByTenantName.put(TenantName.from(key), value.asString()));
- return archiveUrisByTenantName;
- }
-
-}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ArchiveResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ArchiveResponse.java
index 7c844b983d9..84c82d314c9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ArchiveResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ArchiveResponse.java
@@ -4,6 +4,9 @@ package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.restapi.SlimeJsonResponse;
import com.yahoo.slime.Cursor;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.archive.ArchiveUris;
+
+import java.util.Map;
/**
* Returns tenant archive URIs.
@@ -13,11 +16,22 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
public class ArchiveResponse extends SlimeJsonResponse {
public ArchiveResponse(NodeRepository nodeRepository) {
+ ArchiveUris archiveUris = nodeRepository.archiveUriManager().archiveUris();
Cursor archivesArray = slime.setObject().setArray("archives");
- nodeRepository.archiveUriManager().getArchiveUris().forEach((tenant, uri) -> {
+
+ archiveUris.tenantArchiveUris().entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .forEach(entry -> {
+ Cursor archiveObject = archivesArray.addObject();
+ archiveObject.setString("tenant", entry.getKey().value());
+ archiveObject.setString("uri", entry.getValue());
+ });
+ archiveUris.accountArchiveUris().entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .forEach(entry -> {
Cursor archiveObject = archivesArray.addObject();
- archiveObject.setString("tenant", tenant.value());
- archiveObject.setString("uri", uri);
+ archiveObject.setString("account", entry.getKey().value());
+ archiveObject.setString("uri", entry.getValue());
});
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManagerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManagerTest.java
index 0b3ae8183af..8ee72d12f57 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManagerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/archive/ArchiveUriManagerTest.java
@@ -3,10 +3,16 @@ package com.yahoo.vespa.hosted.provision.archive;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Cloud;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.Generation;
@@ -15,10 +21,9 @@ import org.junit.Test;
import java.util.Optional;
-import static com.yahoo.vespa.hosted.provision.archive.ArchiveUriManager.normalizeUri;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
/**
* @author freva
@@ -27,19 +32,35 @@ public class ArchiveUriManagerTest {
@Test
public void archive_uri() {
- ApplicationId app = ApplicationId.from("vespa", "music", "main");
- Node allocated = createNode(app);
- Node unallocated = createNode(null);
- ArchiveUriManager archiveUriManager = new ProvisioningTester.Builder().build().nodeRepository().archiveUriManager();
+ ApplicationId app1 = ApplicationId.from("vespa", "music", "main");
+ ApplicationId app2 = ApplicationId.from("yahoo", "music", "main");
+ CloudAccount account1 = CloudAccount.from("123456789012");
+ CloudAccount account2 = CloudAccount.from("210987654321");
+ CloudAccount accountSystem = CloudAccount.from("555444333222");
+ ArchiveUriManager archiveUriManager = new ProvisioningTester.Builder()
+ .zone(new Zone(Cloud.builder().account(accountSystem).build(), SystemName.Public, Environment.prod, RegionName.defaultName()))
+ .build().nodeRepository().archiveUriManager();
- assertFalse(archiveUriManager.archiveUriFor(unallocated).isPresent());
- assertFalse(archiveUriManager.archiveUriFor(allocated).isPresent());
+ // Initially no uris are set
+ assertFalse(archiveUriManager.archiveUriFor(createNode(null, null)).isPresent());
+ assertFalse(archiveUriManager.archiveUriFor(createNode(app1, account1)).isPresent());
- archiveUriManager.setArchiveUri(app.tenant(), Optional.of("scheme://hostname/dir"));
- assertEquals("scheme://hostname/dir/music/main/default/h432a/", archiveUriManager.archiveUriFor(allocated).get());
+ archiveUriManager.setArchiveUri(app1.tenant(), Optional.of("scheme://tenant-bucket/dir"));
+ archiveUriManager.setArchiveUri(account1, Optional.of("scheme://account-bucket/dir"));
+ assertThrows(IllegalArgumentException.class, () -> archiveUriManager.setArchiveUri(accountSystem, Optional.of("scheme://something")));
+ assertThrows(IllegalArgumentException.class, () -> archiveUriManager.setArchiveUri(CloudAccount.empty, Optional.of("scheme://something")));
+
+ assertFalse(archiveUriManager.archiveUriFor(createNode(null, null)).isPresent()); // Not allocated
+ assertFalse(archiveUriManager.archiveUriFor(createNode(null, account1)).isPresent()); // URI set for this account, but not allocated
+ assertFalse(archiveUriManager.archiveUriFor(createNode(null, account2)).isPresent()); // Not allocated
+ assertFalse(archiveUriManager.archiveUriFor(createNode(app2, null)).isPresent()); // No URI set for this tenant or account
+ assertEquals("scheme://tenant-bucket/dir/music/main/default/h432a/", archiveUriManager.archiveUriFor(createNode(app1, null)).get());
+ assertEquals("scheme://account-bucket/dir/music/main/default/h432a/", archiveUriManager.archiveUriFor(createNode(app1, account1)).get()); // Account has precedence
+ assertFalse(archiveUriManager.archiveUriFor(createNode(app1, account2)).isPresent()); // URI set for this tenant, but is ignored because enclave account
+ assertEquals("scheme://tenant-bucket/dir/music/main/default/h432a/", archiveUriManager.archiveUriFor(createNode(app1, accountSystem)).get()); // URI for tenant because non-enclave acocunt
}
- private Node createNode(ApplicationId appId) {
+ private Node createNode(ApplicationId appId, CloudAccount account) {
Node.Builder nodeBuilder = Node.create("id", "h432a.prod.us-south-1.vespa.domain.tld", new Flavor(NodeResources.unspecified()), Node.State.parked, NodeType.tenant);
Optional.ofNullable(appId)
.map(app -> new Allocation(app,
@@ -48,31 +69,7 @@ public class ArchiveUriManagerTest {
Generation.initial(),
false))
.ifPresent(nodeBuilder::allocation);
+ Optional.ofNullable(account).ifPresent(nodeBuilder::cloudAccount);
return nodeBuilder.build();
}
-
- @Test
- public void normalize_test() {
- assertEquals("ftp://domain/legal-dir123/", normalizeUri("ftp://domain/legal-dir123"));
- assertEquals("ftp://domain/legal-dir123/", normalizeUri("ftp://domain/legal-dir123/"));
- assertEquals("s3://my-bucket-prod.region/my-tenant-123/", normalizeUri("s3://my-bucket-prod.region/my-tenant-123/"));
- assertEquals("s3://my-bucket-prod.region/my-tenant_123/", normalizeUri("s3://my-bucket-prod.region/my-tenant_123/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("domain/dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp:/domain/dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp:/domain//dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp://domain/illegal:dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp://domain/-illegal-dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp://domain/_illegal-dir/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp://domain/illegal-dir-/"));
- assertThrows(IllegalArgumentException.class, () -> normalizeUri("ftp://domain/illegal-dir_/"));
- }
-
- private static void assertThrows(Class<? extends Throwable> clazz, Runnable runnable) {
- try {
- runnable.run();
- fail("Expected " + clazz);
- } catch (Throwable e) {
- if (!clazz.isInstance(e)) throw e;
- }
- }
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializerTest.java
new file mode 100644
index 00000000000..6204ace8a51
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ArchiveUriSerializerTest.java
@@ -0,0 +1,29 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.persistence;
+
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.provision.archive.ArchiveUris;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author freva
+ */
+public class ArchiveUriSerializerTest {
+
+ @Test
+ public void test_serialization() {
+ ArchiveUris archiveUris = new ArchiveUris(Map.of(
+ TenantName.from("tenant1"), "ftp://host123.test/dir/",
+ TenantName.from("tenant2"), "ftp://archive.test/vespa/"),
+ Map.of(CloudAccount.from("321456987012"), "ftp://host123.test/dir/"));
+
+ ArchiveUris serialized = ArchiveUriSerializer.fromJson(ArchiveUriSerializer.toJson(archiveUris));
+ assertEquals(archiveUris, serialized);
+ }
+
+} \ No newline at end of file
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializerTest.java
deleted file mode 100644
index 2ae4f6363e0..00000000000
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/TenantArchiveUriSerializerTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.provision.persistence;
-
-import com.yahoo.config.provision.TenantName;
-import org.junit.Test;
-
-import java.util.Map;
-import java.util.TreeMap;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author freva
- */
-public class TenantArchiveUriSerializerTest {
-
- @Test
- public void test_serialization() {
- Map<TenantName, String> archiveUris = new TreeMap<>();
- archiveUris.put(TenantName.from("tenant1"), "ftp://host123.test/dir/");
- archiveUris.put(TenantName.from("tenant2"), "ftp://archive.test/vespa/");
-
- Map<TenantName, String> serialized = TenantArchiveUriSerializer.fromJson(TenantArchiveUriSerializer.toJson(archiveUris));
- assertEquals(archiveUris, serialized);
- }
-
-} \ No newline at end of file