This is an automated email from the ASF dual-hosted git repository. gilbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 8603cef151f18dd88045c6f942d6dba669fbb735 Author: Qian Zhang <[email protected]> AuthorDate: Wed Feb 27 22:22:06 2019 -0800 Made non-root containers can access PARENT type SANDBOX_PATH volume. If a nested container running as a non-root user tries to use a PARENT type SANDBOX_PATH volume, we will make sure the volume owned by a unique gid allocated by the volume gid manager and the container process launched with that gid as its supplementary group. Review: https://reviews.apache.org/r/69345/ --- include/mesos/slave/containerizer.proto | 3 + src/local/local.cpp | 9 +++ src/slave/containerizer/containerizer.cpp | 5 +- src/slave/containerizer/containerizer.hpp | 5 +- src/slave/containerizer/mesos/containerizer.cpp | 65 +++++++++++++++++++-- src/slave/containerizer/mesos/containerizer.hpp | 9 ++- .../mesos/isolators/volume/sandbox_path.cpp | 67 ++++++++++++++++++++-- .../mesos/isolators/volume/sandbox_path.hpp | 14 ++++- src/slave/containerizer/mesos/launch.cpp | 4 ++ src/slave/main.cpp | 28 ++++++++- src/slave/slave.cpp | 2 + src/slave/slave.hpp | 3 + src/tests/cluster.cpp | 28 ++++++++- src/tests/mock_slave.cpp | 3 + src/tests/mock_slave.hpp | 1 + 15 files changed, 228 insertions(+), 18 deletions(-) diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto index 7d16463..b93b5f4 100644 --- a/include/mesos/slave/containerizer.proto +++ b/include/mesos/slave/containerizer.proto @@ -221,6 +221,9 @@ message ContainerLaunchInfo { // (POSIX only) The user to launch the command as. optional string user = 10; + // (POSIX only) The supplementary group IDs to launch the command as. + repeated uint32 supplementary_groups = 19; + // If specified, it'll become the launch command for the custom // executor, or the launch command for the user task in the case of // a command task. diff --git a/src/local/local.cpp b/src/local/local.cpp index 6087068..6ac6b02 100644 --- a/src/local/local.cpp +++ b/src/local/local.cpp @@ -166,6 +166,7 @@ static vector<Fetcher*>* fetchers = nullptr; static vector<ResourceEstimator*>* resourceEstimators = nullptr; static vector<QoSController*>* qosControllers = nullptr; static vector<SecretGenerator*>* secretGenerators = nullptr; +static vector<SecretResolver*>* secretResolvers = nullptr; PID<Master> launch(const Flags& flags, Allocator* _allocator) @@ -375,6 +376,7 @@ PID<Master> launch(const Flags& flags, Allocator* _allocator) resourceEstimators = new vector<ResourceEstimator*>(); qosControllers = new vector<QoSController*>(); secretGenerators = new vector<SecretGenerator*>(); + secretResolvers = new vector<SecretResolver*>(); vector<UPID> pids; @@ -504,6 +506,8 @@ PID<Master> launch(const Flags& flags, Allocator* _allocator) << "Failed to initialize secret resolver: " << secretResolver.error(); } + secretResolvers->push_back(secretResolver.get()); + Try<Containerizer*> containerizer = Containerizer::create( slaveFlags, true, @@ -529,6 +533,7 @@ PID<Master> launch(const Flags& flags, Allocator* _allocator) resourceEstimators->back(), qosControllers->back(), secretGenerators->back(), + nullptr, authorizer_); // Same authorizer as master. slaves[containerizer.get()] = slave; @@ -601,6 +606,10 @@ void shutdown() delete fetchers; fetchers = nullptr; + foreach (SecretResolver* secretResolver, *secretResolvers) { + delete secretResolver; + } + foreach (SecretGenerator* secretGenerator, *secretGenerators) { delete secretGenerator; } diff --git a/src/slave/containerizer/containerizer.cpp b/src/slave/containerizer/containerizer.cpp index c6b5e64..5ce0d9c 100644 --- a/src/slave/containerizer/containerizer.cpp +++ b/src/slave/containerizer/containerizer.cpp @@ -218,7 +218,8 @@ Try<Containerizer*> Containerizer::create( bool local, Fetcher* fetcher, GarbageCollector* gc, - SecretResolver* secretResolver) + SecretResolver* secretResolver, + VolumeGidManager* volumeGidManager) { // Get the set of containerizer types. const vector<string> _types = strings::split(flags.containerizers, ","); @@ -288,7 +289,7 @@ Try<Containerizer*> Containerizer::create( foreach (const string& type, containerizerTypes) { if (type == "mesos") { Try<MesosContainerizer*> containerizer = MesosContainerizer::create( - flags, local, fetcher, gc, secretResolver, nvidia); + flags, local, fetcher, gc, secretResolver, nvidia, volumeGidManager); if (containerizer.isError()) { return Error("Could not create MesosContainerizer: " + containerizer.error()); diff --git a/src/slave/containerizer/containerizer.hpp b/src/slave/containerizer/containerizer.hpp index 66f73a3..d33c65c 100644 --- a/src/slave/containerizer/containerizer.hpp +++ b/src/slave/containerizer/containerizer.hpp @@ -38,6 +38,8 @@ #include "slave/gc.hpp" +#include "slave/volume_gid_manager/volume_gid_manager.hpp" + #include "slave/containerizer/fetcher.hpp" namespace mesos { @@ -72,7 +74,8 @@ public: bool local, Fetcher* fetcher, GarbageCollector* gc, - SecretResolver* secretResolver = nullptr); + SecretResolver* secretResolver = nullptr, + VolumeGidManager* volumeGidManager = nullptr); // Determine slave resources from flags, probing the system or // querying a delegate. diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp index 5e6b354..a30c00a 100644 --- a/src/slave/containerizer/mesos/containerizer.cpp +++ b/src/slave/containerizer/mesos/containerizer.cpp @@ -176,7 +176,8 @@ Try<MesosContainerizer*> MesosContainerizer::create( Fetcher* fetcher, GarbageCollector* gc, SecretResolver* secretResolver, - const Option<NvidiaComponents>& nvidia) + const Option<NvidiaComponents>& nvidia, + VolumeGidManager* volumeGidManager) { Try<hashset<string>> isolations = [&flags]() -> Try<hashset<string>> { const vector<string> tokens(strings::tokenize(flags.isolation, ",")); @@ -421,7 +422,12 @@ Try<MesosContainerizer*> MesosContainerizer::create( // Volume isolators. #ifndef __WINDOWS__ - {"volume/sandbox_path", &VolumeSandboxPathIsolatorProcess::create}, + {"volume/sandbox_path", + [volumeGidManager] (const Flags& flags) -> Try<Isolator*> { + return VolumeSandboxPathIsolatorProcess::create( + flags, + volumeGidManager); + }}, #endif // __WINDOWS__ #ifdef __linux__ @@ -562,7 +568,8 @@ Try<MesosContainerizer*> MesosContainerizer::create( gc, Owned<Launcher>(launcher.get()), provisioner, - isolators); + isolators, + volumeGidManager); } @@ -573,7 +580,8 @@ Try<MesosContainerizer*> MesosContainerizer::create( GarbageCollector* gc, const Owned<Launcher>& launcher, const Shared<Provisioner>& provisioner, - const vector<Owned<Isolator>>& isolators) + const vector<Owned<Isolator>>& isolators, + VolumeGidManager* volumeGidManager) { // Add I/O switchboard to the isolator list. // @@ -631,6 +639,7 @@ Try<MesosContainerizer*> MesosContainerizer::create( launcher, provisioner, _isolators, + volumeGidManager, initMemFd, commandExecutorMemFd))); } @@ -1443,7 +1452,7 @@ Future<Nothing> MesosContainerizerProcess::prepare( const ContainerID& containerId, const Option<ProvisionInfo>& provisionInfo) { - // This is because if a 'destroy' happens during the provisoiner is + // This is because if a 'destroy' happens during the provisioner is // provisioning in '_launch', even if the '____destroy' will wait // for the 'provision' in '_launch' to finish, there is still a // chance that '____destroy' and its dependencies finish before @@ -1665,6 +1674,17 @@ Future<Containerizer::LaunchResult> MesosContainerizerProcess::_launch( launchInfo.add_clone_namespaces(ns); } + // Remove duplicated entries in supplementary groups. + set<uint32_t> supplementaryGroups( + launchInfo.supplementary_groups().begin(), + launchInfo.supplementary_groups().end()); + + launchInfo.clear_supplementary_groups(); + + foreach (uint32_t gid, supplementaryGroups) { + launchInfo.add_supplementary_groups(gid); + } + // Determine the launch command for the container. if (!launchInfo.has_command()) { launchInfo.mutable_command()->CopyFrom(container->config->command_info()); @@ -2702,6 +2722,41 @@ void MesosContainerizerProcess::____destroy( { CHECK(containers_.contains(containerId)); +#ifndef __WINDOWS__ + if (volumeGidManager) { + const Owned<Container>& container = containers_.at(containerId); + + if (container->config.isSome()) { + VLOG(1) << "Invoking volume gid manager to deallocate gid for container " + << containerId; + + volumeGidManager->deallocate(container->config->directory()) + .onAny(defer(self(), [=](const Future<Nothing>& future) { + CHECK(containers_.contains(containerId)); + + if (!future.isReady()) { + container->termination.fail( + "Failed to deallocate gid when destroying container: " + + (future.isFailed() ? future.failure() : "discarded future")); + + ++metrics.container_destroy_errors; + return; + } + + cleanupIsolators(containerId) + .onAny(defer( + self(), + &Self::_____destroy, + containerId, + termination, + lambda::_1)); + })); + + return; + } + } +#endif // __WINDOWS__ + cleanupIsolators(containerId) .onAny(defer( self(), diff --git a/src/slave/containerizer/mesos/containerizer.hpp b/src/slave/containerizer/mesos/containerizer.hpp index 263a177..558e412 100644 --- a/src/slave/containerizer/mesos/containerizer.hpp +++ b/src/slave/containerizer/mesos/containerizer.hpp @@ -71,7 +71,8 @@ public: Fetcher* fetcher, GarbageCollector* gc = nullptr, SecretResolver* secretResolver = nullptr, - const Option<NvidiaComponents>& nvidia = None()); + const Option<NvidiaComponents>& nvidia = None(), + VolumeGidManager* volumeGidManager = nullptr); static Try<MesosContainerizer*> create( const Flags& flags, @@ -80,7 +81,8 @@ public: GarbageCollector* gc, const process::Owned<Launcher>& launcher, const process::Shared<Provisioner>& provisioner, - const std::vector<process::Owned<mesos::slave::Isolator>>& isolators); + const std::vector<process::Owned<mesos::slave::Isolator>>& isolators, + VolumeGidManager* volumeGidManager = nullptr); ~MesosContainerizer() override; @@ -143,6 +145,7 @@ public: const process::Owned<Launcher>& _launcher, const process::Shared<Provisioner>& _provisioner, const std::vector<process::Owned<mesos::slave::Isolator>>& _isolators, + VolumeGidManager* _volumeGidManager, const Option<int_fd>& _initMemFd, const Option<int_fd>& _commandExecutorMemFd) : ProcessBase(process::ID::generate("mesos-containerizer")), @@ -153,6 +156,7 @@ public: launcher(_launcher), provisioner(_provisioner), isolators(_isolators), + volumeGidManager(_volumeGidManager), initMemFd(_initMemFd), commandExecutorMemFd(_commandExecutorMemFd) {} @@ -339,6 +343,7 @@ private: const process::Owned<Launcher> launcher; const process::Shared<Provisioner> provisioner; const std::vector<process::Owned<mesos::slave::Isolator>> isolators; + VolumeGidManager* volumeGidManager; const Option<int_fd> initMemFd; const Option<int_fd> commandExecutorMemFd; diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp index ecd467c..45bd143 100644 --- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp +++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp @@ -18,6 +18,7 @@ #include <glog/logging.h> +#include <process/collect.hpp> #include <process/future.hpp> #include <process/id.hpp> @@ -62,7 +63,8 @@ namespace internal { namespace slave { Try<Isolator*> VolumeSandboxPathIsolatorProcess::create( - const Flags& flags) + const Flags& flags, + VolumeGidManager* volumeGidManager) { bool bindMountSupported = false; @@ -72,7 +74,12 @@ Try<Isolator*> VolumeSandboxPathIsolatorProcess::create( } Owned<MesosIsolatorProcess> process( - new VolumeSandboxPathIsolatorProcess(flags, bindMountSupported)); + new VolumeSandboxPathIsolatorProcess( + flags, +#ifdef __linux__ + volumeGidManager, +#endif // __linux__ + bindMountSupported)); return new MesosIsolator(process); } @@ -80,9 +87,15 @@ Try<Isolator*> VolumeSandboxPathIsolatorProcess::create( VolumeSandboxPathIsolatorProcess::VolumeSandboxPathIsolatorProcess( const Flags& _flags, +#ifdef __linux__ + VolumeGidManager* _volumeGidManager, +#endif // __linux__ bool _bindMountSupported) : ProcessBase(process::ID::generate("volume-sandbox-path-isolator")), flags(_flags), +#ifdef __linux__ + volumeGidManager(_volumeGidManager), +#endif // __linux__ bindMountSupported(_bindMountSupported) {} @@ -139,6 +152,7 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare( } ContainerLaunchInfo launchInfo; + vector<Future<gid_t>> futures; foreach (const Volume& volume, containerInfo.volumes()) { // NOTE: The validation here is for backwards compatibility. For @@ -249,7 +263,6 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare( // Get 'sourceRoot''s user and group info for the source path. struct stat s; - if (::stat(sourceRoot.c_str(), &s) < 0) { return ErrnoFailure("Failed to stat '" + sourceRoot + "'"); } @@ -380,6 +393,44 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare( source, target, MS_BIND | MS_REC | (volume.mode() == Volume::RO ? MS_RDONLY : 0)); + + // For the PARENT type SANDBOX_PATH volume, if the container's user is + // not root and not the owner of the volume, call volume gid manager to + // allocate a gid to make sure the container has the permission to access + // the volume. Please note that we only do this when `bindMountSupported` + // is true but not for the case of using symlink to do the SANDBOX_PATH + // volume, because container's sandbox is created with 0750 permissions + // (i.e., other users have no permissions, see MESOS-8332 for details), so + // the nested container actually has no permissions to access anything + // under its parent container's sandbox if their users are different, + // that means the nested container cannot access the source path of the + // volume (i.e., the source of the symlink) which is under its parent + // container's sandbox. + if (volumeGidManager && + containerConfig.has_user() && + containerConfig.user() != "root" && + sandboxPath->type() == Volume::Source::SandboxPath::PARENT) { + Result<uid_t> uid = os::getuid(containerConfig.user()); + if (!uid.isSome()) { + return Failure( + "Failed to get the uid of user '" + containerConfig.user() + "': " + + (uid.isError() ? uid.error() : "not found")); + } + + struct stat s; + if (::stat(source.c_str(), &s) < 0) { + return ErrnoFailure("Failed to stat '" + source + "'"); + } + + if (uid.get() != s.st_uid) { + LOG(INFO) << "Invoking volume gid manager to allocate gid to the " + << "volume path '" << source << "' for container " + << containerId; + + futures.push_back( + volumeGidManager->allocate(source, VolumeGidInfo::SANDBOX_PATH)); + } + } #endif // __linux__ } else { LOG(INFO) << "Linking SANDBOX_PATH volume from " @@ -402,7 +453,15 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare( } } - return launchInfo; + return collect(futures) + .then([launchInfo](const vector<gid_t>& gids) mutable + -> Future<Option<ContainerLaunchInfo>> { + foreach (gid_t gid, gids) { + launchInfo.add_supplementary_groups(gid); + } + + return launchInfo; + }); } diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.hpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.hpp index 1631160..07cda22 100644 --- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.hpp +++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.hpp @@ -23,6 +23,8 @@ #include "slave/flags.hpp" +#include "slave/volume_gid_manager/volume_gid_manager.hpp" + #include "slave/containerizer/mesos/isolator.hpp" namespace mesos { @@ -32,7 +34,9 @@ namespace slave { class VolumeSandboxPathIsolatorProcess : public MesosIsolatorProcess { public: - static Try<mesos::slave::Isolator*> create(const Flags& flags); + static Try<mesos::slave::Isolator*> create( + const Flags& flags, + VolumeGidManager* volumeGidManager); ~VolumeSandboxPathIsolatorProcess() override; @@ -53,9 +57,17 @@ public: private: VolumeSandboxPathIsolatorProcess( const Flags& flags, +#ifdef __linux__ + VolumeGidManager* volumeGidManager, +#endif // __linux__ bool bindMountSupported); const Flags flags; + +#ifdef __linux__ + VolumeGidManager* volumeGidManager; +#endif // __linux__ + const bool bindMountSupported; hashmap<ContainerID, std::string> sandboxes; diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp index 17dd671..88b97a5 100644 --- a/src/slave/containerizer/mesos/launch.cpp +++ b/src/slave/containerizer/mesos/launch.cpp @@ -824,6 +824,10 @@ int MesosContainerizerLaunch::execute() exitWithStatus(EXIT_FAILURE); } + foreach (uint32_t supplementaryGroup, launchInfo.supplementary_groups()) { + _gids->push_back(supplementaryGroup); + } + uid = _uid.get(); gid = _gid.get(); gids = _gids.get(); diff --git a/src/slave/main.cpp b/src/slave/main.cpp index d1ce454..344aa66 100644 --- a/src/slave/main.cpp +++ b/src/slave/main.cpp @@ -477,8 +477,27 @@ int main(int argc, char** argv) << "Failed to initialize secret resolver: " << secretResolver.error(); } - Try<Containerizer*> containerizer = - Containerizer::create(flags, false, fetcher, gc, secretResolver.get()); + VolumeGidManager* volumeGidManager = nullptr; + +#ifndef __WINDOWS__ + if (flags.volume_gid_range.isSome()) { + Try<VolumeGidManager*> _volumeGidManager = VolumeGidManager::create(flags); + if (_volumeGidManager.isError()) { + EXIT(EXIT_FAILURE) << "Failed to initialize volume gid manager: " + << _volumeGidManager.error(); + } + + volumeGidManager = _volumeGidManager.get(); + } +#endif // __WINDOWS__ + + Try<Containerizer*> containerizer = Containerizer::create( + flags, + false, + fetcher, + gc, + secretResolver.get(), + volumeGidManager); if (containerizer.isError()) { EXIT(EXIT_FAILURE) @@ -591,6 +610,7 @@ int main(int argc, char** argv) resourceEstimator.get(), qosController.get(), secretGenerator, + volumeGidManager, authorizer_); process::spawn(slave); @@ -616,6 +636,10 @@ int main(int argc, char** argv) delete containerizer.get(); + delete volumeGidManager; + + delete secretResolver.get(); + delete gc; delete fetcher; diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp index f6339e9..3b7870a 100644 --- a/src/slave/slave.cpp +++ b/src/slave/slave.cpp @@ -197,6 +197,7 @@ Slave::Slave(const string& id, ResourceEstimator* _resourceEstimator, QoSController* _qosController, SecretGenerator* _secretGenerator, + VolumeGidManager* _volumeGidManager, const Option<Authorizer*>& _authorizer) : ProcessBase(id), state(RECOVERING), @@ -226,6 +227,7 @@ Slave::Slave(const string& id, resourceEstimator(_resourceEstimator), qosController(_qosController), secretGenerator(_secretGenerator), + volumeGidManager(_volumeGidManager), authorizer(_authorizer), resourceVersion(protobuf::createUUID()) {} diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp index 404f22f..808531c 100644 --- a/src/slave/slave.hpp +++ b/src/slave/slave.hpp @@ -127,6 +127,7 @@ public: mesos::slave::ResourceEstimator* resourceEstimator, mesos::slave::QoSController* qosController, mesos::SecretGenerator* secretGenerator, + VolumeGidManager* volumeGidManager, const Option<Authorizer*>& authorizer); ~Slave() override; @@ -835,6 +836,8 @@ private: mesos::SecretGenerator* secretGenerator; + VolumeGidManager* volumeGidManager; + const Option<Authorizer*> authorizer; // The most recent estimate of the total amount of oversubscribed diff --git a/src/tests/cluster.cpp b/src/tests/cluster.cpp index 6148984..b43f806 100644 --- a/src/tests/cluster.cpp +++ b/src/tests/cluster.cpp @@ -97,6 +97,8 @@ #include "slave/containerizer/containerizer.hpp" #include "slave/containerizer/fetcher.hpp" +#include "slave/volume_gid_manager/volume_gid_manager.hpp" + #include "tests/cluster.hpp" #include "tests/mock_registrar.hpp" @@ -427,6 +429,23 @@ Try<process::Owned<Slave>> Slave::create( slave->gc.reset(new slave::GarbageCollector(flags.work_dir)); } + // If the flag `--volume_gid_range` is specified, create a volume gid manager. + slave::VolumeGidManager* volumeGidManager = nullptr; + +#ifndef __WINDOWS__ + if (flags.volume_gid_range.isSome()) { + Try<slave::VolumeGidManager*> _volumeGidManager = + slave::VolumeGidManager::create(flags); + + if (_volumeGidManager.isError()) { + return Error( + "Failed to create volume gid manager: " + _volumeGidManager.error()); + } + + volumeGidManager = _volumeGidManager.get(); + } +#endif // __WINDOWS__ + // If the containerizer is not provided, create a default one. if (containerizer.isSome()) { slave->containerizer = containerizer.get(); @@ -436,7 +455,12 @@ Try<process::Owned<Slave>> Slave::create( Try<slave::Containerizer*> _containerizer = slave::Containerizer::create( - flags, true, slave->fetcher.get(), gc.getOrElse(slave->gc.get())); + flags, + true, + slave->fetcher.get(), + gc.getOrElse(slave->gc.get()), + nullptr, + volumeGidManager); if (_containerizer.isError()) { return Error("Failed to create containerizer: " + _containerizer.error()); @@ -588,6 +612,7 @@ Try<process::Owned<Slave>> Slave::create( resourceEstimator.getOrElse(slave->resourceEstimator.get()), qosController.getOrElse(slave->qosController.get()), secretGenerator.getOrElse(slave->secretGenerator.get()), + volumeGidManager, authorizer)); } else { slave->slave.reset(new slave::Slave( @@ -601,6 +626,7 @@ Try<process::Owned<Slave>> Slave::create( resourceEstimator.getOrElse(slave->resourceEstimator.get()), qosController.getOrElse(slave->qosController.get()), secretGenerator.getOrElse(slave->secretGenerator.get()), + volumeGidManager, authorizer)); } diff --git a/src/tests/mock_slave.cpp b/src/tests/mock_slave.cpp index a78ca9c..1122c2a 100644 --- a/src/tests/mock_slave.cpp +++ b/src/tests/mock_slave.cpp @@ -36,6 +36,7 @@ using mesos::master::detector::MasterDetector; using mesos::internal::slave::Containerizer; using mesos::internal::slave::GarbageCollector; using mesos::internal::slave::TaskStatusUpdateManager; +using mesos::internal::slave::VolumeGidManager; using mesos::slave::ContainerTermination; using mesos::slave::ResourceEstimator; @@ -101,6 +102,7 @@ MockSlave::MockSlave( ResourceEstimator* resourceEstimator, QoSController* qosController, SecretGenerator* secretGenerator, + VolumeGidManager* volumeGidManager, const Option<Authorizer*>& authorizer) // It is necessary to explicitly call `ProcessBase` constructor here even // though the direct parent `Slave` already does this. This is because @@ -119,6 +121,7 @@ MockSlave::MockSlave( resourceEstimator, qosController, secretGenerator, + volumeGidManager, authorizer) { // Set up default behaviors, calling the original methods. diff --git a/src/tests/mock_slave.hpp b/src/tests/mock_slave.hpp index 3c0d602..326a450 100644 --- a/src/tests/mock_slave.hpp +++ b/src/tests/mock_slave.hpp @@ -99,6 +99,7 @@ public: mesos::slave::ResourceEstimator* resourceEstimator, mesos::slave::QoSController* qosController, SecretGenerator* secretGenerator, + slave::VolumeGidManager* volumeGidManager, const Option<Authorizer*>& authorizer); MOCK_METHOD6(___run, void(
