diff options
author | Valerij Fredriksen <valerijf@yahooinc.com> | 2021-11-03 14:41:52 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@yahooinc.com> | 2021-11-04 09:51:31 +0100 |
commit | ca44ef52f1ea2d79cc7df35c643986a6541aecc6 (patch) | |
tree | 5a199b3ec9c6e3cd3a4de646fe6edd1d74da420d /node-admin | |
parent | 8e165140c2726e4434e56a032aeadd012943dca6 (diff) |
Expose UserScope from NodeAgentContext
Diffstat (limited to 'node-admin')
13 files changed, 199 insertions, 126 deletions
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java index 6fef2cbbb50..452e4e38972 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java @@ -24,9 +24,9 @@ import com.yahoo.vespa.hosted.node.admin.component.ConfigServerInfo; import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentTask; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; import com.yahoo.vespa.hosted.node.admin.task.util.file.FileFinder; import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixPath; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerPath; import javax.net.ssl.HostnameVerifier; @@ -207,7 +207,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { EntityBindingsMapper.toAttestationData(signedIdentityDocument), csr); EntityBindingsMapper.writeSignedIdentityDocumentToFile(identityDocumentFile, signedIdentityDocument); - writePrivateKeyAndCertificate(context.vespaUser(), + writePrivateKeyAndCertificate(context.users().vespa(), privateKeyFile, keyPair.getPrivate(), certificateFile, instanceIdentity.certificate()); context.log(logger, "Instance successfully registered and credentials written to file"); } @@ -235,7 +235,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { context.identity(), identityDocument.providerUniqueId().asDottedString(), csr); - writePrivateKeyAndCertificate(context.vespaUser(), + writePrivateKeyAndCertificate(context.users().vespa(), privateKeyFile, keyPair.getPrivate(), certificateFile, instanceIdentity.certificate()); context.log(logger, "Instance successfully refreshed and credentials written to file"); } catch (ZtsClientException e) { @@ -252,7 +252,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { } - private static void writePrivateKeyAndCertificate(VespaUser vespaUser, + private static void writePrivateKeyAndCertificate(UnixUser vespaUser, ContainerPath privateKeyFile, PrivateKey privateKey, ContainerPath certificateFile, @@ -261,7 +261,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { writeFile(certificateFile, vespaUser, X509CertificateUtils.toPem(certificate)); } - private static void writeFile(ContainerPath path, VespaUser vespaUser, String utf8Content) { + private static void writeFile(ContainerPath path, UnixUser vespaUser, String utf8Content) { new UnixPath(path.resolveSibling(path.getFileName() + ".tmp")) .writeUtf8File(utf8Content, "r--------") .setOwnerId(vespaUser.uid()) diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/servicedump/VespaServiceDumperImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/servicedump/VespaServiceDumperImpl.java index b299e1f3f0d..38722231f54 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/servicedump/VespaServiceDumperImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/servicedump/VespaServiceDumperImpl.java @@ -101,8 +101,8 @@ public class VespaServiceDumperImpl implements VespaServiceDumper { } context.log(log, Level.INFO, "Creating '" + unixPathDirectory +"'."); unixPathDirectory.createDirectory("rwxr-x---") - .setOwner(context.vespaUser().name()) - .setGroup(context.vespaUser().group()); + .setOwner(context.users().vespa().name()) + .setGroup(context.users().vespa().group()); URI destination = serviceDumpDestination(nodeSpec, createDumpId(request)); ProducerContext producerCtx = new ProducerContext(context, directory, request); List<Artifact> producedArtifacts = new ArrayList<>(); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java index 8111f41f9d5..f90e1944948 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java @@ -24,10 +24,10 @@ public interface NodeAgentContext extends TaskContext { /** @return node ACL from node-repository */ Acl acl(); - /** @return name of the docker container this context applies to */ + /** @return name of the linux container this context applies to */ ContainerName containerName(); - /** @return hostname of the docker container this context applies to */ + /** @return hostname of the linux container this context applies to */ default HostName hostname() { return HostName.from(node().hostname()); } @@ -42,10 +42,8 @@ public interface NodeAgentContext extends TaskContext { ZoneApi zone(); - /** @return information about the Vespa user inside the container */ - VespaUser vespaUser(); - - UserNamespace userNamespace(); + /** @return information about users/user namespace of the linux container this context applies to */ + UserScope users(); default boolean isDisabled(NodeAgentTask task) { return false; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java index 037bbc56d1d..82e630a1629 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java @@ -16,6 +16,7 @@ import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.container.ContainerNetworkMode; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerFileSystem; import com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerPath; @@ -99,13 +100,8 @@ public class NodeAgentContextImpl implements NodeAgentContext { } @Override - public VespaUser vespaUser() { - return containerFs.getUserPrincipalLookupService().vespaUser(); - } - - @Override - public UserNamespace userNamespace() { - return containerFs.getUserPrincipalLookupService().userNamespace(); + public UserScope users() { + return containerFs.getUserPrincipalLookupService().userScope(); } @Override @@ -133,7 +129,7 @@ public class NodeAgentContextImpl implements NodeAgentContext { @Override public ContainerPath containerPathFromPathOnHost(Path pathOnHost) { - return ContainerPath.fromPathOnHost(containerFs, pathOnHost); + return ContainerPath.fromPathOnHost(containerFs, pathOnHost, users().root()); } @Override @@ -193,7 +189,7 @@ public class NodeAgentContextImpl implements NodeAgentContext { private ContainerNetworkMode containerNetworkMode; private ZoneApi zone; private UserNamespace userNamespace; - private VespaUser vespaUser; + private UnixUser vespaUser; private Path containerStorage; private FlagSource flagSource; private double cpuSpeedUp = 1; @@ -233,7 +229,7 @@ public class NodeAgentContextImpl implements NodeAgentContext { return this; } - public Builder vespaUser(VespaUser vespaUser) { + public Builder vespaUser(UnixUser vespaUser) { this.vespaUser = vespaUser; return this; } @@ -267,12 +263,11 @@ public class NodeAgentContextImpl implements NodeAgentContext { public NodeAgentContextImpl build() { Objects.requireNonNull(containerStorage, "Must set one of containerStorage or fileSystem"); - UserNamespace userNamespace = Optional.ofNullable(this.userNamespace) - .orElseGet(() -> new UserNamespace(100000, 100000, 100000)); - VespaUser vespaUser = Optional.ofNullable(this.vespaUser) - .orElseGet(() -> new VespaUser("vespa", "vespa", 1000, 100)); + UserScope userScope = UserScope.create( + Optional.ofNullable(vespaUser).orElseGet(() -> new UnixUser("vespa", 1000, "vespa", 100)), + Optional.ofNullable(userNamespace).orElseGet(() -> new UserNamespace(100000, 100000, 100000))); ContainerFileSystem containerFs = ContainerFileSystem.create(containerStorage - .resolve(nodeSpecBuilder.hostname().split("\\.")[0]), userNamespace, vespaUser); + .resolve(nodeSpecBuilder.hostname().split("\\.")[0]), userScope); containerFs.createRoot(); return new NodeAgentContextImpl( diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserScope.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserScope.java new file mode 100644 index 00000000000..0c4c79172e2 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserScope.java @@ -0,0 +1,52 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.nodeagent; + +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; + +import java.util.Objects; + +/** + * @author freva + */ +public class UserScope { + + private final UnixUser root; + private final UnixUser vespa; + private final UserNamespace namespace; + + private UserScope(UnixUser root, UnixUser vespa, UserNamespace namespace) { + this.root = Objects.requireNonNull(root); + this.vespa = Objects.requireNonNull(vespa); + this.namespace = Objects.requireNonNull(namespace); + } + + public UnixUser root() { + return root; + } + + public UnixUser vespa() { + return vespa; + } + + public UserNamespace namespace() { + return namespace; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UserScope userScope = (UserScope) o; + return root.equals(userScope.root) && vespa.equals(userScope.vespa) && namespace.equals(userScope.namespace); + } + + @Override + public int hashCode() { + return Objects.hash(root, vespa, namespace); + } + + /** Creates user scope with default root user */ + public static UserScope create(UnixUser vespaUser, UserNamespace namespace) { + return new UserScope(UnixUser.ROOT, vespaUser, namespace); + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.java deleted file mode 100644 index eb391809e6f..00000000000 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.java +++ /dev/null @@ -1,29 +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.node.admin.nodeagent; - -import java.util.Objects; - -/** - * Describes Vespa user inside the container user namespace. - * - * @author freva - */ -public class VespaUser { - - private final String name; - private final String group; - private final int uid; - private final int gid; - - public VespaUser(String name, String group, int uid, int gid) { - this.name = Objects.requireNonNull(name); - this.group = Objects.requireNonNull(group); - this.uid = uid; - this.gid = gid; - } - - public String name() { return name; } - public String group() { return group; } - public int uid() { return uid; } - public int gid() { return gid; } -} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/UnixUser.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/UnixUser.java new file mode 100644 index 00000000000..665bb4b8bbc --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/UnixUser.java @@ -0,0 +1,57 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.task.util.file; + +import java.util.Objects; + +/** + * A regular UNIX-style user and its primary group. + * + * @author mpolden + */ +public class UnixUser { + + public static final UnixUser ROOT = new UnixUser("root", 0, "root", 0); + + private final String name; + private final int uid; + private final String group; + private final int gid; + + public UnixUser(String name, int uid, String group, int gid) { + this.name = name; + this.uid = uid; + this.group = group; + this.gid = gid; + } + + /** Username of this */ + public String name() { return name; } + + /** User ID of this */ + public int uid() { return uid; } + + /** Primary group of this */ + public String group() { return group; } + + /** Primary group ID of this */ + public int gid() { return gid; } + + @Override + public String toString() { + return "user " + name + ":" + group; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UnixUser unixUser = (UnixUser) o; + return uid == unixUser.uid && name.equals(unixUser.name) && + gid == unixUser.gid && group.equals(unixUser.group); + } + + @Override + public int hashCode() { + return Objects.hash(uid, name, gid, group); + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java index a2c6f63355d..bbcb971b78e 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java @@ -1,8 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.admin.task.util.fs; -import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; import java.io.IOException; import java.nio.file.FileStore; @@ -93,7 +92,7 @@ public class ContainerFileSystem extends FileSystem { throw new UnsupportedOperationException(); } - public static ContainerFileSystem create(Path containerStorageRoot, UserNamespace userNamespace, VespaUser vespaUser) { - return new ContainerFileSystemProvider(containerStorageRoot, userNamespace, vespaUser).getFileSystem(null); + public static ContainerFileSystem create(Path containerStorageRoot, UserScope userScope) { + return new ContainerFileSystemProvider(containerStorageRoot, userScope).getFileSystem(null); } } 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 c956cae868b..0faa54f4487 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 @@ -1,8 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.admin.task.util.fs; -import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import java.io.IOException; import java.net.URI; @@ -45,10 +45,10 @@ class ContainerFileSystemProvider extends FileSystemProvider { private final ContainerFileSystem containerFs; private final ContainerUserPrincipalLookupService userPrincipalLookupService; - ContainerFileSystemProvider(Path containerRootOnHost, UserNamespace userNamespace, VespaUser vespaUser) { + ContainerFileSystemProvider(Path containerRootOnHost, UserScope userScope) { this.containerFs = new ContainerFileSystem(this, containerRootOnHost); this.userPrincipalLookupService = new ContainerUserPrincipalLookupService( - containerRootOnHost.getFileSystem().getUserPrincipalLookupService(), userNamespace, vespaUser); + containerRootOnHost.getFileSystem().getUserPrincipalLookupService(), userScope); } public ContainerUserPrincipalLookupService userPrincipalLookupService() { diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java index 79d43b39f43..60ee92045e0 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java @@ -1,8 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.admin.task.util.fs; -import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import java.io.IOException; import java.nio.file.attribute.GroupPrincipal; @@ -10,6 +10,7 @@ import java.nio.file.attribute.UserPrincipal; import java.nio.file.attribute.UserPrincipalLookupService; import java.nio.file.attribute.UserPrincipalNotFoundException; import java.util.Objects; +import java.util.function.Function; /** * @author freva @@ -17,59 +18,55 @@ import java.util.Objects; public class ContainerUserPrincipalLookupService extends UserPrincipalLookupService { private final UserPrincipalLookupService baseFsUserPrincipalLookupService; - private final UserNamespace userNamespace; - private final VespaUser vespaUser; + private final UserScope userScope; - ContainerUserPrincipalLookupService( - UserPrincipalLookupService baseFsUserPrincipalLookupService, UserNamespace userNamespace, VespaUser vespaUser) { + ContainerUserPrincipalLookupService(UserPrincipalLookupService baseFsUserPrincipalLookupService, UserScope userScope) { this.baseFsUserPrincipalLookupService = Objects.requireNonNull(baseFsUserPrincipalLookupService); - this.userNamespace = Objects.requireNonNull(userNamespace); - this.vespaUser = Objects.requireNonNull(vespaUser); + this.userScope = Objects.requireNonNull(userScope); } - public UserNamespace userNamespace() { return userNamespace; } - public VespaUser vespaUser() { return vespaUser; } + public UserScope userScope() { return userScope; } - public int userIdOnHost(int containerUid) { return userNamespace.userIdOnHost(containerUid); } - public int groupIdOnHost(int containerGid) { return userNamespace.groupIdOnHost(containerGid); } - public int userIdInContainer(int hostUid) { return userNamespace.userIdInContainer(hostUid); } - public int groupIdInContainer(int hostGid) { return userNamespace.groupIdInContainer(hostGid); } + public int userIdOnHost(int containerUid) { return userScope.namespace().userIdOnHost(containerUid); } + public int groupIdOnHost(int containerGid) { return userScope.namespace().groupIdOnHost(containerGid); } + public int userIdInContainer(int hostUid) { return userScope.namespace().userIdInContainer(hostUid); } + public int groupIdInContainer(int hostGid) { return userScope.namespace().groupIdInContainer(hostGid); } @Override public ContainerUserPrincipal lookupPrincipalByName(String name) throws IOException { - int containerUid = resolveName(name, vespaUser.name(), vespaUser.uid()); - String user = resolveId(containerUid, vespaUser.name(), vespaUser.uid()); + int containerUid = resolveName(name, UnixUser::uid, UnixUser::name); + String user = resolveId(containerUid, UnixUser::uid, UnixUser::name); String hostUid = String.valueOf(userIdOnHost(containerUid)); return new ContainerUserPrincipal(containerUid, user, baseFsUserPrincipalLookupService.lookupPrincipalByName(hostUid)); } @Override public ContainerGroupPrincipal lookupPrincipalByGroupName(String group) throws IOException { - int containerGid = resolveName(group, vespaUser.group(), vespaUser.gid()); - String name = resolveId(containerGid, vespaUser.group(), vespaUser.gid()); + int containerGid = resolveName(group, UnixUser::gid, UnixUser::group); + String name = resolveId(containerGid, UnixUser::gid, UnixUser::group); String hostGid = String.valueOf(groupIdOnHost(containerGid)); return new ContainerGroupPrincipal(containerGid, name, baseFsUserPrincipalLookupService.lookupPrincipalByGroupName(hostGid)); } public ContainerUserPrincipal userPrincipal(int uid, UserPrincipal baseFsPrincipal) { - String name = resolveId(uid, vespaUser.name(), vespaUser.uid()); + String name = resolveId(uid, UnixUser::uid, UnixUser::name); return new ContainerUserPrincipal(uid, name, baseFsPrincipal); } public ContainerGroupPrincipal groupPrincipal(int gid, GroupPrincipal baseFsPrincipal) { - String name = resolveId(gid, vespaUser.group(), vespaUser.gid()); + String name = resolveId(gid, UnixUser::gid, UnixUser::group); return new ContainerGroupPrincipal(gid, name, baseFsPrincipal); } - private String resolveId(int id, String vespaName, int vespaId) { - if (id == 0) return "root"; - if (id == vespaId) return vespaName; + private String resolveId(int id, Function<UnixUser, Integer> idExtractor, Function<UnixUser, String> nameExtractor) { + if (idExtractor.apply(userScope.root()) == id) return nameExtractor.apply(userScope.root()); + if (idExtractor.apply(userScope.vespa()) == id) return nameExtractor.apply(userScope.vespa()); return String.valueOf(id); } - private int resolveName(String name, String vespaName, int vespaId) throws UserPrincipalNotFoundException { - if (name.equals("root")) return 0; - if (name.equals(vespaName)) return vespaId; + private int resolveName(String name, Function<UnixUser, Integer> idExtractor, Function<UnixUser, String> nameExtractor) throws UserPrincipalNotFoundException { + if (name.equals(nameExtractor.apply(userScope.root()))) return idExtractor.apply(userScope.root()); + if (name.equals(nameExtractor.apply(userScope.vespa()))) return idExtractor.apply(userScope.vespa()); try { return Integer.parseInt(name); 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 14c1378fbd7..393e1ac34b2 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 @@ -2,8 +2,9 @@ package com.yahoo.vespa.hosted.node.admin.task.util.fs; import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixPath; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import com.yahoo.vespa.test.file.TestFileSystem; import org.junit.jupiter.api.Test; @@ -26,14 +27,12 @@ class ContainerFileSystemTest { private final FileSystem fileSystem = TestFileSystem.create(); private final UnixPath containerRootOnHost = new UnixPath(fileSystem.getPath("/data/storage/ctr1")); - private final UserNamespace userNamespace = new UserNamespace(10_000, 11_000, 10000); - private final VespaUser vespaUser = new VespaUser("vespa", "users", 1000, 100); - private final ContainerFileSystem containerFs = ContainerFileSystem.create( - containerRootOnHost.createDirectories().toPath(), userNamespace, vespaUser); + private final UserScope userScope = UserScope.create(new UnixUser("vespa", 1000, "users", 100), new UserNamespace(10_000, 11_000, 10000)); + private final ContainerFileSystem containerFs = ContainerFileSystem.create(containerRootOnHost.createDirectories().toPath(), userScope); @Test public void creates_files_and_directories_with_container_root_as_owner() throws IOException { - ContainerPath containerPath = ContainerPath.fromPathInContainer(containerFs, Path.of("/opt/vespa/logs/file")); + ContainerPath containerPath = ContainerPath.fromPathInContainer(containerFs, Path.of("/opt/vespa/logs/file"), userScope.root()); UnixPath unixPath = new UnixPath(containerPath).createParents().writeUtf8File("hello world"); for (ContainerPath p = containerPath; p.getParent() != null; p = p.getParent()) @@ -43,14 +42,14 @@ class ContainerFileSystemTest { assertOwnership(containerPath, 500, 1000, 10500, 12000); UnixPath hostFile = new UnixPath(fileSystem.getPath("/file")).createNewFile(); - ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/copy1")); + ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/copy1"), userScope.root()); Files.copy(hostFile.toPath(), destination); assertOwnership(destination, 0, 0, 10000, 11000); } @Test public void file_write_and_read() throws IOException { - ContainerPath containerPath = ContainerPath.fromPathInContainer(containerFs, Path.of("/file")); + ContainerPath containerPath = ContainerPath.fromPathInContainer(containerFs, Path.of("/file"), userScope.root()); UnixPath unixPath = new UnixPath(containerPath); unixPath.writeUtf8File("hello"); assertOwnership(containerPath, 0, 0, 10000, 11000); @@ -66,11 +65,11 @@ class ContainerFileSystemTest { @Test public void copy() throws IOException { UnixPath hostFile = new UnixPath(fileSystem.getPath("/file")).createNewFile(); - ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest")); + ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest"), userScope.root()); // If file is copied to JimFS path, the UID/GIDs are not fixed Files.copy(hostFile.toPath(), destination.pathOnHost()); - assertEquals(String.valueOf(userNamespace.overflowId()), Files.getOwner(destination).getName()); + assertEquals(String.valueOf(userScope.namespace().overflowId()), Files.getOwner(destination).getName()); Files.delete(destination); Files.copy(hostFile.toPath(), destination); @@ -87,7 +86,7 @@ class ContainerFileSystemTest { // Set owner + group and copy within ContainerFS new UnixPath(destination).setOwnerId(500).setGroupId(200); - ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2")); + ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2"), userScope.root()); Files.copy(destination, destination2, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); assertOwnership(destination2, 500, 200, 10500, 11200); } @@ -95,11 +94,11 @@ class ContainerFileSystemTest { @Test public void move() throws IOException { UnixPath hostFile = new UnixPath(fileSystem.getPath("/file")).createNewFile(); - ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest")); + ContainerPath destination = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest"), userScope.root()); // If file is moved to JimFS path, the UID/GIDs are not fixed Files.move(hostFile.toPath(), destination.pathOnHost()); - assertEquals(String.valueOf(userNamespace.overflowId()), Files.getOwner(destination).getName()); + assertEquals(String.valueOf(userScope.namespace().overflowId()), Files.getOwner(destination).getName()); Files.delete(destination); hostFile.createNewFile(); @@ -118,21 +117,21 @@ class ContainerFileSystemTest { // Set owner + group and move within ContainerFS new UnixPath(destination).setOwnerId(500).setGroupId(200); - ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2")); + ContainerPath destination2 = ContainerPath.fromPathInContainer(containerFs, Path.of("/dest2"), userScope.root()); Files.move(destination, destination2, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); assertOwnership(destination2, 500, 200, 10500, 11200); } @Test public void symlink() throws IOException { - ContainerPath source = ContainerPath.fromPathInContainer(containerFs, Path.of("/src")); + ContainerPath source = ContainerPath.fromPathInContainer(containerFs, Path.of("/src"), userScope.root()); // 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"))); + Files.createSymbolicLink(source, ContainerPath.fromPathInContainer(containerFs, Path.of("/path/in/container"), userScope.root())); assertEquals(fileSystem.getPath("/path/in/container"), Files.readSymbolicLink(source)); assertOwnership(source, 0, 0, 10000, 11000); } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerPathTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerPathTest.java index 768db980432..95696798c43 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerPathTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerPathTest.java @@ -1,8 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.admin.task.util.fs; -import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import com.yahoo.vespa.test.file.TestFileSystem; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -14,8 +14,6 @@ import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import static com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerPath.fromPathInContainer; -import static com.yahoo.vespa.hosted.node.admin.task.util.fs.ContainerPath.fromPathOnHost; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -28,28 +26,28 @@ import static org.mockito.Mockito.mock; class ContainerPathTest { private final FileSystem baseFs = TestFileSystem.create(); - private final ContainerFileSystem containerFs = ContainerFileSystem.create(baseFs.getPath("/data/storage/ctr1"), mock(UserNamespace.class), mock(VespaUser.class)); + private final ContainerFileSystem containerFs = ContainerFileSystem.create(baseFs.getPath("/data/storage/ctr1"), mock(UserScope.class)); @Test public void create_new_container_path() { - ContainerPath path = fromPathInContainer(containerFs, Path.of("/opt/vespa//logs/./file")); + ContainerPath path = fromPathInContainer(Path.of("/opt/vespa//logs/./file")); assertPaths(path, "/data/storage/ctr1/opt/vespa/logs/file", "/opt/vespa/logs/file"); - path = fromPathOnHost(containerFs, baseFs.getPath("/data/storage/ctr1/opt/vespa/logs/file")); + path = fromPathOnHost(baseFs.getPath("/data/storage/ctr1/opt/vespa/logs/file")); assertPaths(path, "/data/storage/ctr1/opt/vespa/logs/file", "/opt/vespa/logs/file"); - path = fromPathOnHost(containerFs, baseFs.getPath("/data/storage/ctr2/..////./ctr1/./opt")); + path = fromPathOnHost(baseFs.getPath("/data/storage/ctr2/..////./ctr1/./opt")); assertPaths(path, "/data/storage/ctr1/opt", "/opt"); - assertThrows(() -> fromPathInContainer(containerFs, Path.of("relative/path")), "Path in container must be absolute: relative/path"); - assertThrows(() -> fromPathOnHost(containerFs, baseFs.getPath("relative/path")), "Paths have different roots: /data/storage/ctr1, relative/path"); - assertThrows(() -> fromPathOnHost(containerFs, baseFs.getPath("/data/storage/ctr2")), "Path /data/storage/ctr2 is not under container root /data/storage/ctr1"); - assertThrows(() -> fromPathOnHost(containerFs, baseFs.getPath("/data/storage/ctr1/../ctr2")), "Path /data/storage/ctr2 is not under container root /data/storage/ctr1"); + assertThrows(() -> fromPathInContainer(Path.of("relative/path")), "Path in container must be absolute: relative/path"); + assertThrows(() -> fromPathOnHost(baseFs.getPath("relative/path")), "Paths have different roots: /data/storage/ctr1, relative/path"); + assertThrows(() -> fromPathOnHost(baseFs.getPath("/data/storage/ctr2")), "Path /data/storage/ctr2 is not under container root /data/storage/ctr1"); + assertThrows(() -> fromPathOnHost(baseFs.getPath("/data/storage/ctr1/../ctr2")), "Path /data/storage/ctr2 is not under container root /data/storage/ctr1"); } @Test public void container_path_operations() { - ContainerPath path = fromPathInContainer(containerFs, Path.of("/opt/vespa/logs/file")); + ContainerPath path = fromPathInContainer(Path.of("/opt/vespa/logs/file")); ContainerPath parent = path.getParent(); assertPaths(path.getRoot(), "/data/storage/ctr1", "/"); assertPaths(parent, "/data/storage/ctr1/opt/vespa/logs", "/opt/vespa/logs"); @@ -72,7 +70,7 @@ class ContainerPathTest { @Test public void resolution() { - ContainerPath path = fromPathInContainer(containerFs, Path.of("/opt/vespa/logs")); + ContainerPath path = fromPathInContainer(Path.of("/opt/vespa/logs")); assertPaths(path.resolve(Path.of("/root")), "/data/storage/ctr1/root", "/root"); assertPaths(path.resolve(Path.of("relative")), "/data/storage/ctr1/opt/vespa/logs/relative", "/opt/vespa/logs/relative"); assertPaths(path.resolve(Path.of("/../../../dir2/../../../dir2")), "/data/storage/ctr1/dir2", "/dir2"); @@ -84,7 +82,7 @@ class ContainerPathTest { @Test public void resolves_real_paths() throws IOException { - ContainerPath path = fromPathInContainer(containerFs, Path.of("/opt/vespa/logs")); + ContainerPath path = fromPathInContainer(Path.of("/opt/vespa/logs")); Files.createDirectories(path.pathOnHost().getParent()); Files.createFile(baseFs.getPath("/data/storage/ctr1/opt/vespa/target1")); @@ -103,6 +101,13 @@ class ContainerPathTest { assertThrows(path::toRealPath, "Path /data/storage/ctr2 is not under container root /data/storage/ctr1"); } + private ContainerPath fromPathInContainer(Path pathInContainer) { + return ContainerPath.fromPathInContainer(containerFs, pathInContainer, UnixUser.ROOT); + } + private ContainerPath fromPathOnHost(Path pathOnHost) { + return ContainerPath.fromPathOnHost(containerFs, pathOnHost, UnixUser.ROOT); + } + private static void assertPaths(ContainerPath actual, String expectedPathOnHost, String expectedPathInContainer) { assertEquals(expectedPathOnHost, actual.pathOnHost().toString()); assertEquals(expectedPathInContainer, actual.pathInContainer()); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupServiceTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupServiceTest.java index 40db3250ca3..72eec92cf53 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupServiceTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupServiceTest.java @@ -2,7 +2,8 @@ package com.yahoo.vespa.hosted.node.admin.task.util.fs; import com.yahoo.vespa.hosted.node.admin.nodeagent.UserNamespace; -import com.yahoo.vespa.hosted.node.admin.nodeagent.VespaUser; +import com.yahoo.vespa.hosted.node.admin.nodeagent.UserScope; +import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixUser; import com.yahoo.vespa.test.file.TestFileSystem; import org.junit.jupiter.api.Test; @@ -19,10 +20,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows; */ class ContainerUserPrincipalLookupServiceTest { - private final UserNamespace userNamespace = new UserNamespace(10_000, 11_000, 10000); - private final VespaUser vespaUser = new VespaUser("vespa", "users", 1000, 100); + private final UserScope userScope = UserScope.create(new UnixUser("vespa", 1000, "users", 100), new UserNamespace(10_000, 11_000, 10000)); private final ContainerUserPrincipalLookupService userPrincipalLookupService = - new ContainerUserPrincipalLookupService(TestFileSystem.create().getUserPrincipalLookupService(), userNamespace, vespaUser); + new ContainerUserPrincipalLookupService(TestFileSystem.create().getUserPrincipalLookupService(), userScope); @Test public void correctly_resolves_ids() throws IOException { |