You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2024/07/31 22:54:02 UTC
(mesos) 01/03: [cgroups2] Introduces the DeviceControllerProcess.
This is an automated email from the ASF dual-hosted git repository.
bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 8038681524f9b0efaacf77e09e7933ea7ca999ee
Author: Jason Zhou <ja...@gmail.com>
AuthorDate: Wed Jul 31 15:27:47 2024 -0700
[cgroups2] Introduces the DeviceControllerProcess.
Introduces a device controller that supports cgroups v2 and is available
in the Cgroups2IsolatorProcess. Device access control is made through
the DeviceManager.
Review: https://reviews.apache.org/r/75098/
---
src/CMakeLists.txt | 1 +
src/Makefile.am | 2 +
.../mesos/isolators/cgroups2/constants.hpp | 1 +
.../isolators/cgroups2/controllers/devices.cpp | 204 +++++++++++++++++++++
.../isolators/cgroups2/controllers/devices.hpp | 82 +++++++++
5 files changed, 290 insertions(+)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9526ed17a..50684b615 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -349,6 +349,7 @@ set(LINUX_SRC
slave/containerizer/mesos/isolators/cgroups2/controllers/core.cpp
slave/containerizer/mesos/isolators/cgroups2/controllers/cpu.cpp
slave/containerizer/mesos/isolators/cgroups2/controllers/memory.cpp
+ slave/containerizer/mesos/isolators/cgroups2/controllers/devices.cpp
slave/containerizer/mesos/isolators/cgroups2/controllers/perf_event.cpp
slave/containerizer/device_manager/device_manager.cpp)
diff --git a/src/Makefile.am b/src/Makefile.am
index 456942389..5b91319d6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1497,6 +1497,8 @@ MESOS_LINUX_FILES = \
slave/containerizer/mesos/isolators/cgroups2/controllers/memory.hpp \
slave/containerizer/mesos/isolators/cgroups2/controllers/perf_event.cpp \
slave/containerizer/mesos/isolators/cgroups2/controllers/perf_event.hpp \
+ slave/containerizer/mesos/isolators/cgroups2/controllers/devices.cpp \
+ slave/containerizer/mesos/isolators/cgroups2/controllers/devices.hpp \
slave/containerizer/device_manager/device_manager.cpp \
slave/containerizer/device_manager/device_manager.hpp
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp b/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
index bad79ad0c..5e6426694 100644
--- a/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/constants.hpp
@@ -39,6 +39,7 @@ const std::string CGROUPS2_CONTROLLER_CORE_NAME = "core";
const std::string CGROUPS2_CONTROLLER_CPU_NAME = "cpu";
const std::string CGROUPS2_CONTROLLER_MEMORY_NAME = "memory";
const std::string CGROUPS2_CONTROLLER_PERF_EVENT_NAME = "perf_event";
+const std::string CGROUPS2_CONTROLLER_DEVICES_NAME = "devices";
} // namespace slave {
} // namespace internal {
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.cpp b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.cpp
new file mode 100644
index 000000000..702ed50b0
--- /dev/null
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.cpp
@@ -0,0 +1,204 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <sys/stat.h>
+
+// This header include must be enclosed in an `extern "C"` block to
+// workaround a bug in glibc <= 2.12 (see MESOS-7378).
+//
+// TODO(neilc): Remove this when we no longer support glibc <= 2.12.
+extern "C" {
+#include <sys/sysmacros.h>
+}
+
+#include <process/defer.hpp>
+#include <process/id.hpp>
+
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+#include <stout/os.hpp>
+
+#include "slave/containerizer/mesos/isolators/cgroups2/constants.hpp"
+#include "slave/containerizer/mesos/isolators/cgroups2/controllers/devices.hpp"
+
+using cgroups::devices::Entry;
+
+using process::Failure;
+using process::Future;
+using process::Owned;
+
+using std::string;
+using std::vector;
+
+namespace mesos {
+namespace internal {
+namespace slave {
+
+// The default list of devices to whitelist when device isolation is
+// turned on. The full list of devices can be found here:
+// https://www.kernel.org/doc/Documentation/devices.txt
+//
+// Device whitelisting is described here:
+// https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt
+static const char* DEFAULT_WHITELIST_ENTRIES[] = {
+ "c *:* m", // Make new character devices.
+ "b *:* m", // Make new block devices.
+ "c 5:1 rwm", // /dev/console
+ "c 4:0 rwm", // /dev/tty0
+ "c 4:1 rwm", // /dev/tty1
+ "c 136:* rwm", // /dev/pts/*
+ "c 5:2 rwm", // /dev/ptmx
+ "c 10:200 rwm", // /dev/net/tun
+ "c 1:3 rwm", // /dev/null
+ "c 1:5 rwm", // /dev/zero
+ "c 1:7 rwm", // /dev/full
+ "c 5:0 rwm", // /dev/tty
+ "c 1:9 rwm", // /dev/urandom
+ "c 1:8 rwm", // /dev/random
+};
+
+
+Try<Owned<ControllerProcess>> DeviceControllerProcess::create(
+ const Flags& flags,
+ const Owned<DeviceManager> deviceManager)
+{
+ vector<cgroups::devices::Entry> whitelistDeviceEntries;
+
+ foreach (const char* _entry, DEFAULT_WHITELIST_ENTRIES) {
+ whitelistDeviceEntries.push_back(
+ CHECK_NOTERROR(cgroups::devices::Entry::parse(_entry)));
+ }
+
+ if (flags.allowed_devices.isSome()) {
+ foreach (const DeviceAccess& device_access,
+ flags.allowed_devices->allowed_devices()) {
+ if (!device_access.device().has_path()) {
+ return Error("Whitelisted device has no device path provided");
+ }
+
+ const string& path = device_access.device().path();
+ const DeviceAccess_Access& access = device_access.access();
+
+ if (!(access.read() || access.write() || access.mknod())) {
+ return Error("Could not whitelist device '" + path + "'"
+ " without any access privileges");
+ }
+
+ Try<dev_t> device = os::stat::rdev(path);
+ if (device.isError()) {
+ return Error("Failed to obtain device ID for '" + path + "'"
+ ": " + device.error());
+ }
+
+ Try<mode_t> mode = os::stat::mode(path);
+ if (mode.isError()) {
+ return Error("Failed to obtain device mode for '" + path + "'"
+ ": " + mode.error());
+ }
+
+ Entry::Selector::Type type;
+ if (S_ISBLK(mode.get())) {
+ type = Entry::Selector::Type::BLOCK;
+ } else if (S_ISCHR(mode.get())) {
+ type = Entry::Selector::Type::CHARACTER;
+ } else {
+ return Error("Failed to determine device type for '" + path + "'");
+ }
+
+ cgroups::devices::Entry entry;
+ entry.selector.type = type;
+ entry.selector.major = major(device.get());
+ entry.selector.minor = minor(device.get());
+ entry.access.read = access.read();
+ entry.access.write = access.write();
+ entry.access.mknod = access.mknod();
+
+ whitelistDeviceEntries.push_back(entry);
+ }
+ }
+
+ return Owned<ControllerProcess>(new DeviceControllerProcess(
+ flags, whitelistDeviceEntries, deviceManager));
+}
+
+
+string DeviceControllerProcess::name() const
+{
+ return CGROUPS2_CONTROLLER_DEVICES_NAME;
+}
+
+
+DeviceControllerProcess::DeviceControllerProcess(
+ const Flags& _flags,
+ const std::vector<cgroups::devices::Entry>& _whitelistDeviceEntries,
+ const Owned<DeviceManager> _deviceManager)
+ : ProcessBase(process::ID::generate("cgroups-v2-devices-controller")),
+ ControllerProcess(_flags),
+ whitelistDeviceEntries(_whitelistDeviceEntries),
+ deviceManager(_deviceManager) {}
+
+
+Future<Nothing> DeviceControllerProcess::recover(
+ const ContainerID& containerId,
+ const string& cgroup)
+{
+ // TODO(jasonzhou): Work with device manager recovery.
+ if (containerIds.contains(containerId)) {
+ return Failure(
+ "The controller '" + name() + "' of container " +
+ stringify(containerId) + " has already been recovered");
+ }
+
+ containerIds.insert(containerId);
+
+ return Nothing();
+}
+
+
+Future<Nothing> DeviceControllerProcess::prepare(
+ const ContainerID& containerId,
+ const string& cgroup,
+ const mesos::slave::ContainerConfig& containerConfig)
+{
+ if (containerIds.contains(containerId)) {
+ return Failure("The controller '" + name() + "' has already been prepared");
+ }
+
+ return deviceManager->configure(cgroup, whitelistDeviceEntries, {})
+ .then(defer(self(), [=] {
+ containerIds.insert(containerId);
+ return Nothing();
+ }));
+}
+
+
+Future<Nothing> DeviceControllerProcess::cleanup(
+ const ContainerID& containerId,
+ const string& cgroup)
+{
+ if (!containerIds.contains(containerId)) {
+ VLOG(1) << "Ignoring cleanup controller '" << name() << "'"
+ << " for unknown container " << containerId;
+ return Nothing();
+ }
+
+ containerIds.erase(containerId);
+ return deviceManager->remove(cgroup);
+}
+
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
diff --git a/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.hpp b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.hpp
new file mode 100644
index 000000000..c8a2fa34f
--- /dev/null
+++ b/src/slave/containerizer/mesos/isolators/cgroups2/controllers/devices.hpp
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __DEVICES_HPP__
+#define __DEVICES_HPP__
+
+#include <string>
+#include <vector>
+
+#include <process/owned.hpp>
+
+#include <stout/hashset.hpp>
+#include <stout/try.hpp>
+
+#include "linux/cgroups.hpp"
+
+#include "slave/flags.hpp"
+
+#include "slave/containerizer/mesos/isolators/cgroups2/controller.hpp"
+#include "slave/containerizer/device_manager/device_manager.hpp"
+
+namespace mesos {
+namespace internal {
+namespace slave {
+
+/**
+ * Represent cgroups v2 devices controller.
+ */
+class DeviceControllerProcess: public ControllerProcess
+{
+public:
+ static Try<process::Owned<ControllerProcess>> create(
+ const Flags& flags,
+ process::Owned<DeviceManager> deviceManager
+ );
+
+ ~DeviceControllerProcess() override = default;
+
+ std::string name() const override;
+
+ process::Future<Nothing> prepare(
+ const ContainerID& containerId,
+ const std::string& cgroup,
+ const mesos::slave::ContainerConfig& containerConfig) override;
+
+ process::Future<Nothing> recover(
+ const ContainerID& containerId,
+ const std::string& cgroup) override;
+
+ process::Future<Nothing> cleanup(
+ const ContainerID& containerId,
+ const std::string& cgroup) override;
+
+private:
+ DeviceControllerProcess(
+ const Flags& flags,
+ const std::vector<cgroups::devices::Entry>& whitelistDeviceEntries,
+ process::Owned<DeviceManager> deviceManager);
+
+ hashset<ContainerID> containerIds;
+ std::vector<cgroups::devices::Entry> whitelistDeviceEntries;
+ process::Owned<DeviceManager> deviceManager;
+};
+
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __DEVICES_HPP__