From 48b75e3915d1c6b612b364717d0c7e858669f0ba Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Fri, 15 Oct 2021 16:59:03 +0200 Subject: Create ContainerFileSystemCache --- .../node/admin/nodeadmin/NodeAdminStateUpdater.java | 6 +----- .../node/admin/nodeagent/NodeAgentContextImpl.java | 19 ++++++++++--------- .../node/admin/task/util/fs/ContainerFileSystem.java | 2 +- .../util/fs/ContainerUserPrincipalLookupService.java | 4 +++- .../node/admin/integration/ContainerTester.java | 2 +- .../admin/nodeadmin/NodeAdminStateUpdaterTest.java | 6 +----- 6 files changed, 17 insertions(+), 22 deletions(-) (limited to 'node-admin/src') diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java index 53c9e741f59..dda404797d9 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdater.java @@ -3,7 +3,6 @@ package com.yahoo.vespa.hosted.node.admin.nodeadmin; import com.yahoo.concurrent.ThreadFactoryFactory; import com.yahoo.config.provision.HostName; -import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeRepository; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; @@ -13,7 +12,6 @@ import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextFactory; import com.yahoo.yolean.Exceptions; -import java.time.Clock; import java.time.Duration; import java.util.ArrayList; import java.util.EnumSet; @@ -59,9 +57,7 @@ public class NodeAdminStateUpdater { NodeRepository nodeRepository, Orchestrator orchestrator, NodeAdmin nodeAdmin, - HostName hostHostname, - Clock clock, - FlagSource flagSource) { + HostName hostHostname) { this.nodeAgentContextFactory = nodeAgentContextFactory; this.nodeRepository = nodeRepository; this.orchestrator = orchestrator; 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 9bcf5d58d6e..011efbcef62 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 @@ -42,16 +42,14 @@ public class NodeAgentContextImpl implements NodeAgentContext { private final ZoneApi zone; private final ContainerFileSystem containerFs; private final ContainerPath pathToVespaHome; - private final UserNamespace userNamespace; private final double cpuSpeedup; private final Set disabledNodeAgentTasks; private final Optional hostExclusiveTo; public NodeAgentContextImpl(NodeSpec node, Acl acl, AthenzIdentity identity, ContainerNetworkMode containerNetworkMode, ZoneApi zone, - FlagSource flagSource, Path pathToContainerStorage, String pathToVespaHome, - UserNamespace userNamespace, double cpuSpeedup, - Optional hostExclusiveTo) { + FlagSource flagSource, ContainerFileSystem containerFs, String pathToVespaHome, + double cpuSpeedup, Optional hostExclusiveTo) { if (cpuSpeedup <= 0) throw new IllegalArgumentException("cpuSpeedUp must be positive, was: " + cpuSpeedup); @@ -61,10 +59,9 @@ public class NodeAgentContextImpl implements NodeAgentContext { this.identity = Objects.requireNonNull(identity); this.containerNetworkMode = Objects.requireNonNull(containerNetworkMode); this.zone = Objects.requireNonNull(zone); - this.containerFs = ContainerFileSystem.create(pathToContainerStorage.resolve(containerName.asString()), userNamespace); + this.containerFs = Objects.requireNonNull(containerFs); this.pathToVespaHome = containerFs.getPath(pathToVespaHome); this.logPrefix = containerName.asString() + ": "; - this.userNamespace = Objects.requireNonNull(userNamespace); this.cpuSpeedup = cpuSpeedup; this.disabledNodeAgentTasks = NodeAgentTask.fromString( PermanentFlags.DISABLED_HOST_ADMIN_TASKS.bindTo(flagSource).with(FetchVector.Dimension.HOSTNAME, node.hostname()).value()); @@ -103,7 +100,7 @@ public class NodeAgentContextImpl implements NodeAgentContext { @Override public UserNamespace userNamespace() { - return userNamespace; + return containerFs.getUserPrincipalLookupService().userNamespace(); } @Override @@ -258,6 +255,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, "vespa", "vespa", 1000, 100)); + ContainerFileSystem containerFs = ContainerFileSystem.create(containerStorage + .resolve(nodeSpecBuilder.hostname().split("\\.")[0]), userNamespace); + return new NodeAgentContextImpl( nodeSpecBuilder.build(), Optional.ofNullable(acl).orElse(Acl.EMPTY), @@ -285,9 +287,8 @@ public class NodeAgentContextImpl implements NodeAgentContext { } }), Optional.ofNullable(flagSource).orElseGet(InMemoryFlagSource::new), - containerStorage, + containerFs, "/opt/vespa", - Optional.ofNullable(userNamespace).orElseGet(() -> new UserNamespace(100000, 100000, "vespa", "vespa", 1000, 100)), cpuSpeedUp, hostExclusiveTo); } } 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 078a60ba7a5..5b4767ace15 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 @@ -52,7 +52,7 @@ public class ContainerFileSystem extends FileSystem { } @Override - public UserPrincipalLookupService getUserPrincipalLookupService() { + public ContainerUserPrincipalLookupService getUserPrincipalLookupService() { return containerFsProvider.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 ae65f6a7f7f..0e03d052d90 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 @@ -13,7 +13,7 @@ import java.util.Objects; /** * @author valerijf */ -class ContainerUserPrincipalLookupService extends UserPrincipalLookupService { +public class ContainerUserPrincipalLookupService extends UserPrincipalLookupService { private final UserPrincipalLookupService baseFsUserPrincipalLookupService; private final UserNamespace userNamespace; @@ -23,6 +23,8 @@ class ContainerUserPrincipalLookupService extends UserPrincipalLookupService { this.userNamespace = Objects.requireNonNull(userNamespace); } + public UserNamespace userNamespace() { return userNamespace; } + 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); } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java index 08e335f188a..4a26195dd3a 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java @@ -93,7 +93,7 @@ public class ContainerTester implements AutoCloseable { NodeAgentContextFactory nodeAgentContextFactory = (nodeSpec, acl) -> NodeAgentContextImpl.builder(nodeSpec).acl(acl).fileSystem(fileSystem).build(); nodeAdminStateUpdater = new NodeAdminStateUpdater(nodeAgentContextFactory, nodeRepository, orchestrator, - nodeAdmin, HOST_HOSTNAME, clock, flagSource); + nodeAdmin, HOST_HOSTNAME); loopThread = new Thread(() -> { nodeAdminStateUpdater.start(); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdaterTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdaterTest.java index f9b0070a3d6..5436f84f467 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdaterTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminStateUpdaterTest.java @@ -3,8 +3,6 @@ package com.yahoo.vespa.hosted.node.admin.nodeadmin; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.NodeType; -import com.yahoo.test.ManualClock; -import com.yahoo.vespa.flags.InMemoryFlagSource; 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.configserver.noderepository.NodeState; @@ -50,11 +48,9 @@ public class NodeAdminStateUpdaterTest { private final Orchestrator orchestrator = mock(Orchestrator.class); private final NodeAdmin nodeAdmin = mock(NodeAdmin.class); private final HostName hostHostname = HostName.from("basehost1.test.yahoo.com"); - private final ManualClock clock = new ManualClock(); - private final InMemoryFlagSource flagSource = new InMemoryFlagSource(); private final NodeAdminStateUpdater updater = spy(new NodeAdminStateUpdater( - nodeAgentContextFactory, nodeRepository, orchestrator, nodeAdmin, hostHostname, clock, flagSource)); + nodeAgentContextFactory, nodeRepository, orchestrator, nodeAdmin, hostHostname)); @Test -- cgit v1.2.3 From 22b95d0a04cb70c24063a2964b0b8c5e5e5c04b5 Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Mon, 18 Oct 2021 11:47:56 +0200 Subject: Split VespaUser out of UserNamespace --- .../identity/AthenzCredentialsMaintainer.java | 15 +++++------ .../servicedump/VespaServiceDumperImpl.java | 4 +-- .../node/admin/nodeagent/NodeAgentContext.java | 3 ++- .../node/admin/nodeagent/NodeAgentContextImpl.java | 17 ++++++++++--- .../hosted/node/admin/nodeagent/UserNamespace.java | 17 +------------ .../hosted/node/admin/nodeagent/VespaUser.java | 29 ++++++++++++++++++++++ .../admin/task/util/fs/ContainerFileSystem.java | 6 ++--- .../task/util/fs/ContainerFileSystemProvider.java | 5 ++-- .../fs/ContainerUserPrincipalLookupService.java | 19 ++++++++------ .../node/admin/nodeagent/UserNamespaceTest.java | 2 +- .../task/util/fs/ContainerFileSystemTest.java | 7 ++++-- .../node/admin/task/util/fs/ContainerPathTest.java | 3 ++- .../ContainerUserPrincipalLookupServiceTest.java | 6 +++-- 13 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.java (limited to 'node-admin/src') 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 280e58c91f1..a237ec6dd4f 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,6 +24,7 @@ import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.component.ConfigServerInfo; 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.fs.ContainerPath; @@ -206,7 +207,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { EntityBindingsMapper.toAttestationData(signedIdentityDocument), csr); EntityBindingsMapper.writeSignedIdentityDocumentToFile(identityDocumentFile, signedIdentityDocument); - writePrivateKeyAndCertificate(context.userNamespace().vespaUserId(), + writePrivateKeyAndCertificate(context.vespaUser(), privateKeyFile, keyPair.getPrivate(), certificateFile, instanceIdentity.certificate()); context.log(logger, "Instance successfully registered and credentials written to file"); } @@ -234,7 +235,7 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { context.identity(), identityDocument.providerUniqueId().asDottedString(), csr); - writePrivateKeyAndCertificate(context.userNamespace().vespaUserId(), + writePrivateKeyAndCertificate(context.vespaUser(), privateKeyFile, keyPair.getPrivate(), certificateFile, instanceIdentity.certificate()); context.log(logger, "Instance successfully refreshed and credentials written to file"); } catch (ZtsClientException e) { @@ -251,19 +252,19 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer { } - private static void writePrivateKeyAndCertificate(int vespaUid, + private static void writePrivateKeyAndCertificate(VespaUser vespaUser, ContainerPath privateKeyFile, PrivateKey privateKey, ContainerPath certificateFile, X509Certificate certificate) { - writeFile(privateKeyFile, vespaUid, KeyUtils.toPem(privateKey)); - writeFile(certificateFile, vespaUid, X509CertificateUtils.toPem(certificate)); + writeFile(privateKeyFile, vespaUser, KeyUtils.toPem(privateKey)); + writeFile(certificateFile, vespaUser, X509CertificateUtils.toPem(certificate)); } - private static void writeFile(ContainerPath path, int vespaUid, String utf8Content) { + private static void writeFile(ContainerPath path, VespaUser vespaUser, String utf8Content) { new UnixPath(path.resolveSibling(path.getFileName() + ".tmp")) .writeUtf8File(utf8Content, "r--------") - .setOwnerId(vespaUid) + .setOwnerId(vespaUser.uid()) .atomicMove(path); } 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 0a9496be0a6..b299e1f3f0d 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.userNamespace().vespaUser()) - .setGroup(context.userNamespace().vespaGroup()); + .setOwner(context.vespaUser().name()) + .setGroup(context.vespaUser().group()); URI destination = serviceDumpDestination(nodeSpec, createDumpId(request)); ProducerContext producerCtx = new ProducerContext(context, directory, request); List 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 8cf8553bc34..f3148cc7859 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 @@ -42,7 +42,8 @@ public interface NodeAgentContext extends TaskContext { ZoneApi zone(); - UserNamespace userNamespace(); + /** @return information about the Vespa user inside the container */ + VespaUser vespaUser(); 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 011efbcef62..771528324e0 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 @@ -99,8 +99,8 @@ public class NodeAgentContextImpl implements NodeAgentContext { } @Override - public UserNamespace userNamespace() { - return containerFs.getUserPrincipalLookupService().userNamespace(); + public VespaUser vespaUser() { + return containerFs.getUserPrincipalLookupService().vespaUser(); } @Override @@ -188,6 +188,7 @@ public class NodeAgentContextImpl implements NodeAgentContext { private ContainerNetworkMode containerNetworkMode; private ZoneApi zone; private UserNamespace userNamespace; + private VespaUser vespaUser; private Path containerStorage; private FlagSource flagSource; private double cpuSpeedUp = 1; @@ -227,6 +228,12 @@ public class NodeAgentContextImpl implements NodeAgentContext { return this; } + public Builder vespaUser(VespaUser vespaUser) { + this.vespaUser = vespaUser; + return this; + } + + /** Sets the file system to use for paths. */ public Builder fileSystem(FileSystem fileSystem) { return containerStorage(fileSystem.getPath(DEFAULT_CONTAINER_STORAGE.toString())); @@ -256,9 +263,11 @@ public class NodeAgentContextImpl implements NodeAgentContext { Objects.requireNonNull(containerStorage, "Must set one of containerStorage or fileSystem"); UserNamespace userNamespace = Optional.ofNullable(this.userNamespace) - .orElseGet(() -> new UserNamespace(100000, 100000, "vespa", "vespa", 1000, 100)); + .orElseGet(() -> new UserNamespace(100000, 100000)); + VespaUser vespaUser = Optional.ofNullable(this.vespaUser) + .orElseGet(() -> new VespaUser("vespa", "vespa", 1000, 100)); ContainerFileSystem containerFs = ContainerFileSystem.create(containerStorage - .resolve(nodeSpecBuilder.hostname().split("\\.")[0]), userNamespace); + .resolve(nodeSpecBuilder.hostname().split("\\.")[0]), userNamespace, vespaUser); return new NodeAgentContextImpl( nodeSpecBuilder.build(), diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java index 1a25b5c3c5e..46918013e3b 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java @@ -1,8 +1,6 @@ // 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; - /** * @author valerijf */ @@ -18,18 +16,10 @@ public class UserNamespace { private final int uidOffset; private final int gidOffset; - private final String vespaUser; - private final String vespaGroup; - private final int vespaUserId; - private final int vespaGroupId; - public UserNamespace(int uidOffset, int gidOffset, String vespaUser, String vespaGroup, int vespaUserId, int vespaGroupId) { + public UserNamespace(int uidOffset, int gidOffset) { this.uidOffset = uidOffset; this.gidOffset = gidOffset; - this.vespaUser = Objects.requireNonNull(vespaUser); - this.vespaGroup = Objects.requireNonNull(vespaGroup); - this.vespaUserId = vespaUserId; - this.vespaGroupId = vespaGroupId; } public int userIdOnHost(int containerUid) { return toHostId(containerUid, uidOffset); } @@ -37,11 +27,6 @@ public class UserNamespace { public int userIdInContainer(int hostUid) { return toContainerId(hostUid, uidOffset); } public int groupIdInContainer(int hostGid) { return toContainerId(hostGid, gidOffset); } - public String vespaUser() { return vespaUser; } - public String vespaGroup() { return vespaGroup; } - public int vespaUserId() { return vespaUserId; } - public int vespaGroupId() { return vespaGroupId; } - public int idRange() { return ID_RANGE; } public int overflowId() { return OVERFLOW_ID; } 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 new file mode 100644 index 00000000000..78ccca80beb --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/VespaUser.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.node.admin.nodeagent; + +import java.util.Objects; + +/** + * Describes Vespa user inside the container user namespace. + * + * @author valerijf + */ +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/fs/ContainerFileSystem.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/fs/ContainerFileSystem.java index 5b4767ace15..cda806f533a 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 @@ -2,6 +2,7 @@ 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 java.io.IOException; import java.nio.file.FileStore; @@ -10,7 +11,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.WatchService; -import java.nio.file.attribute.UserPrincipalLookupService; import java.util.Set; import static com.yahoo.yolean.Exceptions.uncheck; @@ -86,8 +86,8 @@ public class ContainerFileSystem extends FileSystem { throw new UnsupportedOperationException(); } - public static ContainerFileSystem create(Path containerStorageRoot, UserNamespace userNamespace) { + public static ContainerFileSystem create(Path containerStorageRoot, UserNamespace userNamespace, VespaUser vespaUser) { uncheck(() -> Files.createDirectories(containerStorageRoot)); - return new ContainerFileSystemProvider(containerStorageRoot, userNamespace).getFileSystem(null); + return new ContainerFileSystemProvider(containerStorageRoot, userNamespace, vespaUser).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 909c6c9cbc1..bcc35426d25 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 @@ -2,6 +2,7 @@ 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 java.io.IOException; import java.net.URI; @@ -45,10 +46,10 @@ class ContainerFileSystemProvider extends FileSystemProvider { private final ContainerUserPrincipalLookupService userPrincipalLookupService; private final Path containerRootOnHost; - ContainerFileSystemProvider(Path containerRootOnHost, UserNamespace userNamespace) { + ContainerFileSystemProvider(Path containerRootOnHost, UserNamespace userNamespace, VespaUser vespaUser) { this.containerFs = new ContainerFileSystem(this); this.userPrincipalLookupService = new ContainerUserPrincipalLookupService( - containerRootOnHost.getFileSystem().getUserPrincipalLookupService(), userNamespace); + containerRootOnHost.getFileSystem().getUserPrincipalLookupService(), userNamespace, vespaUser); this.containerRootOnHost = containerRootOnHost; } 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 0e03d052d90..8e35bdccc23 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 @@ -2,6 +2,7 @@ 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 java.io.IOException; import java.nio.file.attribute.GroupPrincipal; @@ -17,13 +18,17 @@ public class ContainerUserPrincipalLookupService extends UserPrincipalLookupServ private final UserPrincipalLookupService baseFsUserPrincipalLookupService; private final UserNamespace userNamespace; + private final VespaUser vespaUser; - ContainerUserPrincipalLookupService(UserPrincipalLookupService baseFsUserPrincipalLookupService, UserNamespace userNamespace) { + ContainerUserPrincipalLookupService( + UserPrincipalLookupService baseFsUserPrincipalLookupService, UserNamespace userNamespace, VespaUser vespaUser) { this.baseFsUserPrincipalLookupService = Objects.requireNonNull(baseFsUserPrincipalLookupService); this.userNamespace = Objects.requireNonNull(userNamespace); + this.vespaUser = Objects.requireNonNull(vespaUser); } public UserNamespace userNamespace() { return userNamespace; } + public VespaUser vespaUser() { return vespaUser; } public int userIdOnHost(int containerUid) { return userNamespace.userIdOnHost(containerUid); } public int groupIdOnHost(int containerGid) { return userNamespace.groupIdOnHost(containerGid); } @@ -32,27 +37,27 @@ public class ContainerUserPrincipalLookupService extends UserPrincipalLookupServ @Override public ContainerUserPrincipal lookupPrincipalByName(String name) throws IOException { - int containerUid = resolveName(name, userNamespace.vespaUser(), userNamespace.vespaUserId()); - String user = resolveId(containerUid, userNamespace.vespaUser(), userNamespace.vespaUserId()); + int containerUid = resolveName(name, vespaUser.name(), vespaUser.uid()); + String user = resolveId(containerUid, vespaUser.name(), vespaUser.uid()); 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, userNamespace.vespaGroup(), userNamespace.vespaGroupId()); - String name = resolveId(containerGid, userNamespace.vespaGroup(), userNamespace.vespaGroupId()); + int containerGid = resolveName(group, vespaUser.group(), vespaUser.gid()); + String name = resolveId(containerGid, vespaUser.group(), vespaUser.gid()); 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, userNamespace.vespaUser(), userNamespace.vespaUserId()); + String name = resolveId(uid, vespaUser.name(), vespaUser.uid()); return new ContainerUserPrincipal(uid, name, baseFsPrincipal); } public ContainerGroupPrincipal groupPrincipal(int gid, GroupPrincipal baseFsPrincipal) { - String name = resolveId(gid, userNamespace.vespaGroup(), userNamespace.vespaGroupId()); + String name = resolveId(gid, vespaUser.group(), vespaUser.gid()); return new ContainerGroupPrincipal(gid, name, baseFsPrincipal); } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespaceTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespaceTest.java index 73b59a17c37..bb02667a550 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespaceTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespaceTest.java @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; */ class UserNamespaceTest { - private final UserNamespace userNamespace = new UserNamespace(1000, 2000, "vespa", "users", 1000, 100); + private final UserNamespace userNamespace = new UserNamespace(1000, 2000); @Test public void translates_between_ids() { 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 4e85052a176..242a2458f07 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,6 +2,7 @@ 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.task.util.file.UnixPath; import com.yahoo.vespa.test.file.TestFileSystem; import org.junit.jupiter.api.Test; @@ -24,8 +25,10 @@ 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, "vespa", "users", 1000, 100); - private final ContainerFileSystem containerFs = ContainerFileSystem.create(containerRootOnHost.createDirectories().toPath(), userNamespace); + private final UserNamespace userNamespace = new UserNamespace(10_000, 11_000); + private final VespaUser vespaUser = new VespaUser("vespa", "users", 1000, 100); + private final ContainerFileSystem containerFs = ContainerFileSystem.create( + containerRootOnHost.createDirectories().toPath(), userNamespace, vespaUser); @Test public void creates_files_and_directories_with_container_root_as_owner() throws IOException { 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 6bca8c2f0b1..a2a036008bc 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 @@ -2,6 +2,7 @@ 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.test.file.TestFileSystem; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -27,7 +28,7 @@ import java.nio.file.Path; class ContainerPathTest { private final FileSystem baseFs = TestFileSystem.create(); - private final ContainerFileSystem containerFs = ContainerFileSystem.create(baseFs.getPath("/data/storage/ctr1"), mock(UserNamespace.class)); + private final ContainerFileSystem containerFs = ContainerFileSystem.create(baseFs.getPath("/data/storage/ctr1"), mock(UserNamespace.class), mock(VespaUser.class)); @Test public void create_new_container_path() { 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 bc26cfa73f3..70c837e6fb2 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,6 +2,7 @@ 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.test.file.TestFileSystem; import org.junit.jupiter.api.Test; @@ -18,9 +19,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; */ class ContainerUserPrincipalLookupServiceTest { - private final UserNamespace userNamespace = new UserNamespace(10_000, 11_000, "vespa", "users", 1000, 100); + private final UserNamespace userNamespace = new UserNamespace(10_000, 11_000); + private final VespaUser vespaUser = new VespaUser("vespa", "users", 1000, 100); private final ContainerUserPrincipalLookupService userPrincipalLookupService = - new ContainerUserPrincipalLookupService(TestFileSystem.create().getUserPrincipalLookupService(), userNamespace); + new ContainerUserPrincipalLookupService(TestFileSystem.create().getUserPrincipalLookupService(), userNamespace, vespaUser); @Test public void correctly_resolves_ids() throws IOException { -- cgit v1.2.3 From f10e0ff6ea6f888797f45cb7685df69d89d56ffd Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Mon, 18 Oct 2021 14:40:58 +0200 Subject: Add method to update user namespace ID offsets for migration --- .../yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'node-admin/src') diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java index 46918013e3b..005452411bd 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/UserNamespace.java @@ -14,8 +14,8 @@ public class UserNamespace { * https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/Documentation/admin-guide/sysctl/fs.rst#overflowgid--overflowuid */ private static final int OVERFLOW_ID = 65_534; - private final int uidOffset; - private final int gidOffset; + private volatile int uidOffset; + private volatile int gidOffset; public UserNamespace(int uidOffset, int gidOffset) { this.uidOffset = uidOffset; @@ -30,6 +30,12 @@ public class UserNamespace { public int idRange() { return ID_RANGE; } public int overflowId() { return OVERFLOW_ID; } + // Remove after migration to mapped namespaces is complete, make fields final + public void setOffsets(int idOffset) { + this.uidOffset = idOffset; + this.gidOffset = idOffset; + } + private static int toHostId(int containerId, int idOffset) { if (containerId < 0 || containerId > ID_RANGE) throw new IllegalArgumentException("Invalid container id: " + containerId); -- cgit v1.2.3