diff options
author | Valerij Fredriksen <valerijf@yahooinc.com> | 2021-10-15 11:48:53 +0200 |
---|---|---|
committer | Valerij Fredriksen <valerijf@yahooinc.com> | 2021-10-15 11:48:53 +0200 |
commit | fa2aa2c40a3028752d861592f4a9b37982b80797 (patch) | |
tree | 520ac7d961bd50ac289718413a43c3214a4c51b4 | |
parent | 7f1f9e3d1d17d176c13d183d4131f58c808c2141 (diff) |
Add support for symlinks
2 files changed, 61 insertions, 1 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemProvider.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemProvider.java index 73cd3f8cfc5..a85e4ee8699 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemProvider.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemProvider.java @@ -121,6 +121,20 @@ class ContainerFileSystemProvider extends FileSystemProvider { } @Override + public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) throws IOException { + Path pathOnHost = pathOnHost(link); + if (target instanceof ContainerPath) + target = pathOnHost.getFileSystem().getPath(toContainerPath(target).pathInContainer()); + provider(pathOnHost).createSymbolicLink(pathOnHost, target, attrs); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + Path pathOnHost = pathOnHost(link); + return provider(pathOnHost).readSymbolicLink(pathOnHost); + } + + @Override public boolean isSameFile(Path path, Path path2) throws IOException { // 'path' FS provider should be 'this' if (path2 instanceof ContainerPath) @@ -250,7 +264,7 @@ class ContainerFileSystemProvider extends FileSystemProvider { private static <T> T cast(Object value, Class<T> type) { if (type.isInstance(value)) return type.cast(value); - throw new ProviderMismatchException("Expected " + type.getName() + ", was " + value.getClass().getName()); + throw new ProviderMismatchException("Expected " + type.getSimpleName() + ", was " + value.getClass().getName()); } private static Path pathOnHost(Path path) { diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemTest.java index eb15450b756..fcd8e0ec406 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemTest.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.util.Map; import static com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerUserPrincipalLookupService.OVERFLOW_ID; @@ -52,6 +54,21 @@ class ContainerFileSystemTest { Files.copy(hostFile.toPath(), destination); assertOwnership(destination, 0, 0, 10000, 11000); + + // Set owner + group on both source host file and destination container file + hostFile.setOwnerId(5).setGroupId(10); + new UnixPath(destination).setOwnerId(500).setGroupId(200); + assertOwnership(destination, 500, 200, 10500, 11200); + // Copy the host file to destination again with COPY_ATTRIBUTES and REPLACE_EXISTING + Files.copy(hostFile.toPath(), destination, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + // The destination is recreated, so the owner should be root + assertOwnership(destination, 0, 0, 10000, 11000); + + // Set owner + group and copy within ContainerFS + new UnixPath(destination).setOwnerId(500).setGroupId(200); + ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2")); + Files.copy(destination, destination2, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + assertOwnership(destination2, 0, 0, 10000, 11000); } @Test @@ -67,6 +84,35 @@ class ContainerFileSystemTest { hostFile.createNewFile(); Files.move(hostFile.toPath(), destination); assertOwnership(destination, 0, 0, 10000, 11000); + + // Set owner + group on both source host file and destination container file + hostFile.createNewFile(); + hostFile.setOwnerId(5).setGroupId(10); + new UnixPath(destination).setOwnerId(500).setGroupId(200); + assertOwnership(destination, 500, 200, 10500, 11200); + // Move the host file to destination again with COPY_ATTRIBUTES and REPLACE_EXISTING + Files.move(hostFile.toPath(), destination, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + // The destination is recreated, so the owner should be root + assertOwnership(destination, 0, 0, 10000, 11000); + + // Set owner + group and move within ContainerFS + new UnixPath(destination).setOwnerId(500).setGroupId(200); + ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2")); + Files.move(destination, destination2, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + assertOwnership(destination2, 0, 0, 10000, 11000); + } + + @Test + public void symlink() throws IOException { + ContainerPath source = ContainerPath.fromPathInContainer(containerFs, Path.of("/src")); + // Symlink from ContainerPath to some relative path (different FS provider) + Files.createSymbolicLink(source, fileSystem.getPath("../relative/target")); + assertEquals(fileSystem.getPath("../relative/target"), Files.readSymbolicLink(source)); + Files.delete(source); + + // Symlinks from ContainerPath to a ContainerPath: Target is resolved within container with base FS provider + Files.createSymbolicLink(source, ContainerPath.fromPathInContainer(containerFs, Path.of("/path/in/container"))); + assertEquals(fileSystem.getPath("/path/in/container"), Files.readSymbolicLink(source)); } private static void assertOwnership(ContainerPath path, int contUid, int contGid, int hostUid, int hostGid) throws IOException { |