summaryrefslogtreecommitdiffstats
path: root/node-admin
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@yahooinc.com>2021-11-03 14:41:52 +0100
committerValerij Fredriksen <valerijf@yahooinc.com>2021-11-04 09:51:31 +0100
commitca44ef52f1ea2d79cc7df35c643986a6541aecc6 (patch)
tree5a199b3ec9c6e3cd3a4de646fe6edd1d74da420d /node-admin
parent8e165140c2726e4434e56a032aeadd012943dca6 (diff)
Expose UserScope from NodeAgentContext
Diffstat (limited to 'node-admin')
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java10
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/servicedump/VespaServiceDumperImpl.java4
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java10
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java25
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserScope.java52
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.java29
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/UnixUser.java57
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java7
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemProvider.java8
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupService.java49
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystemTest.java31
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerPathTest.java35
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerUserPrincipalLookupServiceTest.java8
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 {