feat: 初始代码
AM初始代码,迁移自gitlabwh Log: Task: https://pms.uniontech.com/task-view-108539.html Influence: Change-Id: I6096f97e5d68d13796ff5dc51d9858c0f40264a0
This commit is contained in:
544
src/modules/util/oci_runtime.h
Normal file
544
src/modules/util/oci_runtime.h
Normal file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
|
||||
*
|
||||
* Author: Iceyer <me@iceyer.net>
|
||||
*
|
||||
* Maintainer: Iceyer <me@iceyer.net>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_
|
||||
#define LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
#define LLJS_FROM(KEY) (o.KEY = j.at(#KEY).get<decltype(o.KEY)>())
|
||||
#define LLJS_FROM_OPT(KEY) (o.KEY = optional<decltype(o.KEY)::value_type>(j, #KEY))
|
||||
|
||||
#define LLJS_TO(KEY) (j[#KEY] = o.KEY)
|
||||
|
||||
#define LLJS_FROM_OBJ(TYPE) inline void from_json(const nlohmann::json &j, TYPE &o)
|
||||
#define LLJS_TO_OBJ(TYPE) inline void to_json(nlohmann::json &j, const TYPE &o)
|
||||
|
||||
#undef linux
|
||||
|
||||
struct Root {
|
||||
std::string path;
|
||||
tl::optional<bool> readonly;
|
||||
};
|
||||
|
||||
LLJS_FROM_OBJ(Root)
|
||||
{
|
||||
LLJS_FROM(path);
|
||||
LLJS_FROM_OPT(readonly);
|
||||
}
|
||||
|
||||
LLJS_TO_OBJ(Root)
|
||||
{
|
||||
LLJS_TO(path);
|
||||
LLJS_TO(readonly);
|
||||
}
|
||||
|
||||
struct Process {
|
||||
util::str_vec args;
|
||||
util::str_vec env;
|
||||
std::string cwd;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Process &o)
|
||||
{
|
||||
o.args = j.at("args").get<util::str_vec>();
|
||||
o.env = j.at("env").get<util::str_vec>();
|
||||
o.cwd = j.at("cwd").get<std::string>();
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Process &o)
|
||||
{
|
||||
j["args"] = o.args;
|
||||
j["env"] = o.env;
|
||||
j["cwd"] = o.cwd;
|
||||
}
|
||||
|
||||
struct Mount {
|
||||
enum Type {
|
||||
Unknown,
|
||||
Bind,
|
||||
Proc,
|
||||
Sysfs,
|
||||
Devpts,
|
||||
Mqueue,
|
||||
Tmpfs,
|
||||
Cgroup,
|
||||
Cgroup2,
|
||||
};
|
||||
std::string destination;
|
||||
std::string type;
|
||||
std::string source;
|
||||
util::str_vec data;
|
||||
|
||||
Type fsType;
|
||||
uint32_t flags = 0u;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Mount &o)
|
||||
{
|
||||
static std::map<std::string, Mount::Type> fsTypes = {
|
||||
{"bind", Mount::Bind}, {"proc", Mount::Proc}, {"devpts", Mount::Devpts}, {"mqueue", Mount::Mqueue},
|
||||
{"tmpfs", Mount::Tmpfs}, {"sysfs", Mount::Sysfs}, {"cgroup", Mount::Cgroup}, {"cgroup2", Mount::Cgroup2},
|
||||
};
|
||||
|
||||
struct mountFlag {
|
||||
bool clear;
|
||||
uint32_t flag;
|
||||
};
|
||||
|
||||
static std::map<std::string, mountFlag> optionFlags = {
|
||||
{"acl", {false, MS_POSIXACL}},
|
||||
{"async", {true, MS_SYNCHRONOUS}},
|
||||
{"atime", {true, MS_NOATIME}},
|
||||
{"bind", {false, MS_BIND}},
|
||||
{"defaults", {false, 0}},
|
||||
{"dev", {true, MS_NODEV}},
|
||||
{"diratime", {true, MS_NODIRATIME}},
|
||||
{"dirsync", {false, MS_DIRSYNC}},
|
||||
{"exec", {true, MS_NOEXEC}},
|
||||
{"iversion", {false, MS_I_VERSION}},
|
||||
{"lazytime", {false, MS_LAZYTIME}},
|
||||
{"loud", {true, MS_SILENT}},
|
||||
{"mand", {false, MS_MANDLOCK}},
|
||||
{"noacl", {true, MS_POSIXACL}},
|
||||
{"noatime", {false, MS_NOATIME}},
|
||||
{"nodev", {false, MS_NODEV}},
|
||||
{"nodiratime", {false, MS_NODIRATIME}},
|
||||
{"noexec", {false, MS_NOEXEC}},
|
||||
{"noiversion", {true, MS_I_VERSION}},
|
||||
{"nolazytime", {true, MS_LAZYTIME}},
|
||||
{"nomand", {true, MS_MANDLOCK}},
|
||||
{"norelatime", {true, MS_RELATIME}},
|
||||
{"nostrictatime", {true, MS_STRICTATIME}},
|
||||
{"nosuid", {false, MS_NOSUID}},
|
||||
// {"nosymfollow",{false, MS_NOSYMFOLLOW}}, // since kernel 5.10
|
||||
{"rbind", {false, MS_BIND | MS_REC}},
|
||||
{"relatime", {false, MS_RELATIME}},
|
||||
{"remount", {false, MS_REMOUNT}},
|
||||
{"ro", {false, MS_RDONLY}},
|
||||
{"rw", {true, MS_RDONLY}},
|
||||
{"silent", {false, MS_SILENT}},
|
||||
{"strictatime", {false, MS_STRICTATIME}},
|
||||
{"suid", {true, MS_NOSUID}},
|
||||
{"sync", {false, MS_SYNCHRONOUS}},
|
||||
// {"symfollow",{true, MS_NOSYMFOLLOW}}, // since kernel 5.10
|
||||
};
|
||||
|
||||
o.destination = j.at("destination").get<std::string>();
|
||||
o.type = j.at("type").get<std::string>();
|
||||
o.fsType = fsTypes.find(o.type)->second;
|
||||
if (o.fsType == Mount::Bind) {
|
||||
o.flags = MS_BIND;
|
||||
}
|
||||
o.source = j.at("source").get<std::string>();
|
||||
o.data = {};
|
||||
|
||||
// Parse options to data and flags.
|
||||
// FIXME: support "propagation flags" and "recursive mount attrs"
|
||||
// https://github.com/opencontainers/runc/blob/c83abc503de7e8b3017276e92e7510064eee02a8/libcontainer/specconv/spec_linux.go#L958
|
||||
auto options = j.value("options", util::str_vec());
|
||||
for (auto const &opt : options) {
|
||||
auto it = optionFlags.find(opt);
|
||||
if (it != optionFlags.end()) {
|
||||
if (it->second.clear) {
|
||||
o.flags &= ~it->second.flag;
|
||||
} else
|
||||
o.flags |= it->second.flag;
|
||||
} else {
|
||||
o.data.push_back(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Mount &o)
|
||||
{
|
||||
j["destination"] = o.destination;
|
||||
j["source"] = o.source;
|
||||
j["type"] = o.type;
|
||||
j["options"] = o.data; // FIXME: this data is not original options, some of them have been prased to flags.
|
||||
}
|
||||
|
||||
struct Namespace {
|
||||
int type;
|
||||
};
|
||||
|
||||
static std::map<std::string, int> namespaceType = {
|
||||
{"pid", CLONE_NEWPID}, {"uts", CLONE_NEWUTS}, {"mount", CLONE_NEWNS}, {"cgroup", CLONE_NEWCGROUP},
|
||||
{"network", CLONE_NEWNET}, {"ipc", CLONE_NEWIPC}, {"user", CLONE_NEWUSER},
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Namespace &o)
|
||||
{
|
||||
o.type = namespaceType.find(j.at("type").get<std::string>())->second;
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Namespace &o)
|
||||
{
|
||||
auto matchPair = std::find_if(std::begin(namespaceType), std::end(namespaceType),
|
||||
[&](const std::pair<std::string, int> &pair) { return pair.second == o.type; });
|
||||
j["type"] = matchPair->first;
|
||||
}
|
||||
|
||||
struct IDMap {
|
||||
uint64_t containerID = 0u;
|
||||
uint64_t hostID = 0u;
|
||||
uint64_t size = 0u;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, IDMap &o)
|
||||
{
|
||||
o.hostID = j.value("hostID", 0);
|
||||
o.containerID = j.value("containerID", 0);
|
||||
o.size = j.value("size", 0);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const IDMap &o)
|
||||
{
|
||||
j["hostID"] = o.hostID;
|
||||
j["containerID"] = o.containerID;
|
||||
j["size"] = o.size;
|
||||
}
|
||||
|
||||
typedef std::string SeccompAction;
|
||||
typedef std::string SeccompArch;
|
||||
|
||||
struct SyscallArg {
|
||||
u_int index; // require
|
||||
u_int64_t value; // require
|
||||
u_int64_t valueTwo; // optional
|
||||
std::string op; // require
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, SyscallArg &o)
|
||||
{
|
||||
o.index = j.at("index").get<u_int>();
|
||||
o.value = j.at("value").get<u_int64_t>();
|
||||
o.valueTwo = j.value("valueTwo", u_int64_t());
|
||||
o.op = j.at("op").get<std::string>();
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const SyscallArg &o)
|
||||
{
|
||||
j["index"] = o.index;
|
||||
j["value"] = o.value;
|
||||
j["valueTwo"] = o.valueTwo;
|
||||
j["op"] = o.op;
|
||||
}
|
||||
|
||||
struct Syscall {
|
||||
util::str_vec names;
|
||||
SeccompAction action;
|
||||
std::vector<SyscallArg> args;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Syscall &o)
|
||||
{
|
||||
o.names = j.at("names").get<util::str_vec>();
|
||||
o.action = j.at("action").get<SeccompAction>();
|
||||
o.args = j.value("args", std::vector<SyscallArg>());
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Syscall &o)
|
||||
{
|
||||
j["names"] = o.names;
|
||||
j["action"] = o.action;
|
||||
j["args"] = o.args;
|
||||
}
|
||||
|
||||
struct Seccomp {
|
||||
SeccompAction defaultAction = "INVALID_ACTION";
|
||||
std::vector<SeccompArch> architectures;
|
||||
std::vector<Syscall> syscalls;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Seccomp &o)
|
||||
{
|
||||
o.defaultAction = j.at("defaultAction").get<std::string>();
|
||||
o.architectures = j.value("architectures", std::vector<SeccompArch> {});
|
||||
o.syscalls = j.value("syscalls", std::vector<Syscall> {});
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Seccomp &o)
|
||||
{
|
||||
j["defaultAction"] = o.defaultAction;
|
||||
j["architectures"] = o.architectures;
|
||||
j["syscalls"] = o.syscalls;
|
||||
}
|
||||
|
||||
// https://github.com/containers/crun/blob/main/crun.1.md#memory-controller
|
||||
struct ResourceMemory {
|
||||
int64_t limit = -1;
|
||||
int64_t reservation = -1;
|
||||
int64_t swap = -1;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, ResourceMemory &o)
|
||||
{
|
||||
o.limit = j.value("limit", -1);
|
||||
o.reservation = j.value("reservation", -1);
|
||||
o.swap = j.value("swap", -1);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const ResourceMemory &o)
|
||||
{
|
||||
j["limit"] = o.limit;
|
||||
j["reservation"] = o.reservation;
|
||||
j["swap"] = o.swap;
|
||||
}
|
||||
|
||||
// https://github.com/containers/crun/blob/main/crun.1.md#cpu-controller
|
||||
// support v1 and v2 with conversion
|
||||
struct ResourceCPU {
|
||||
u_int64_t shares = 1024;
|
||||
int64_t quota = 100000;
|
||||
u_int64_t period = 100000;
|
||||
// int64_t realtimeRuntime;
|
||||
// int64_t realtimePeriod;
|
||||
// std::string cpus;
|
||||
// std::string mems;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, ResourceCPU &o)
|
||||
{
|
||||
o.shares = j.value("shares", 1024);
|
||||
o.quota = j.value("quota", 100000);
|
||||
o.period = j.value("period", 100000);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const ResourceCPU &o)
|
||||
{
|
||||
j["shares"] = o.shares;
|
||||
j["quota"] = o.quota;
|
||||
j["period"] = o.period;
|
||||
}
|
||||
|
||||
struct Resources {
|
||||
ResourceMemory memory;
|
||||
ResourceCPU cpu;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Resources &o)
|
||||
{
|
||||
o.cpu = j.value("cpu", ResourceCPU());
|
||||
o.memory = j.value("memory", ResourceMemory());
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Resources &o)
|
||||
{
|
||||
j["cpu"] = o.cpu;
|
||||
j["memory"] = o.memory;
|
||||
}
|
||||
|
||||
struct Linux {
|
||||
std::vector<Namespace> namespaces;
|
||||
std::vector<IDMap> uidMappings;
|
||||
std::vector<IDMap> gidMappings;
|
||||
tl::optional<Seccomp> seccomp;
|
||||
std::string cgroupsPath;
|
||||
Resources resources;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Linux &o)
|
||||
{
|
||||
o.namespaces = j.at("namespaces").get<std::vector<Namespace>>();
|
||||
o.uidMappings = j.value("uidMappings", std::vector<IDMap> {});
|
||||
o.gidMappings = j.value("gidMappings", std::vector<IDMap> {});
|
||||
o.seccomp = optional<decltype(o.seccomp)::value_type>(j, "seccomp");
|
||||
o.cgroupsPath = j.value("cgroupsPath", "");
|
||||
o.resources = j.value("resources", Resources());
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Linux &o)
|
||||
{
|
||||
j["namespaces"] = o.namespaces;
|
||||
j["uidMappings"] = o.uidMappings;
|
||||
j["gidMappings"] = o.gidMappings;
|
||||
j["seccomp"] = o.seccomp;
|
||||
j["cgroupsPath"] = o.cgroupsPath;
|
||||
j["resources"] = o.resources;
|
||||
}
|
||||
|
||||
/*
|
||||
"hooks": {
|
||||
"prestart": [
|
||||
{
|
||||
"path": "/usr/bin/fix-mounts",
|
||||
"args": ["fix-mounts", "arg1", "arg2"],
|
||||
"env": [ "key1=value1"]
|
||||
},
|
||||
{
|
||||
"path": "/usr/bin/setup-network"
|
||||
}
|
||||
],
|
||||
"poststart": [
|
||||
{
|
||||
"path": "/usr/bin/notify-start",
|
||||
"timeout": 5
|
||||
}
|
||||
],
|
||||
"poststop": [
|
||||
{
|
||||
"path": "/usr/sbin/cleanup.sh",
|
||||
"args": ["cleanup.sh", "-f"]
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
struct Hook {
|
||||
std::string path;
|
||||
tl::optional<util::str_vec> args;
|
||||
tl::optional<std::vector<std::string>> env;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Hook &o)
|
||||
{
|
||||
LLJS_FROM(path);
|
||||
LLJS_FROM_OPT(args);
|
||||
LLJS_FROM_OPT(env);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Hook &o)
|
||||
{
|
||||
j["path"] = o.path;
|
||||
j["args"] = o.args;
|
||||
j["env"] = o.env;
|
||||
}
|
||||
|
||||
struct Hooks {
|
||||
tl::optional<std::vector<Hook>> prestart;
|
||||
tl::optional<std::vector<Hook>> poststart;
|
||||
tl::optional<std::vector<Hook>> poststop;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Hooks &o)
|
||||
{
|
||||
LLJS_FROM_OPT(prestart);
|
||||
LLJS_FROM_OPT(poststart);
|
||||
LLJS_FROM_OPT(poststop);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Hooks &o)
|
||||
{
|
||||
j["poststop"] = o.poststop;
|
||||
j["poststart"] = o.poststart;
|
||||
j["prestart"] = o.prestart;
|
||||
}
|
||||
|
||||
struct AnnotationsOverlayfs {
|
||||
std::string lower_parent;
|
||||
std::string upper;
|
||||
std::string workdir;
|
||||
std::vector<Mount> mounts;
|
||||
};
|
||||
|
||||
LLJS_FROM_OBJ(AnnotationsOverlayfs)
|
||||
{
|
||||
LLJS_FROM(lower_parent);
|
||||
LLJS_FROM(upper);
|
||||
LLJS_FROM(workdir);
|
||||
LLJS_FROM(mounts);
|
||||
}
|
||||
|
||||
LLJS_TO_OBJ(AnnotationsOverlayfs)
|
||||
{
|
||||
LLJS_TO(lower_parent);
|
||||
LLJS_TO(upper);
|
||||
LLJS_TO(workdir);
|
||||
LLJS_TO(mounts);
|
||||
}
|
||||
|
||||
struct AnnotationsNativeRootfs {
|
||||
std::vector<Mount> mounts;
|
||||
};
|
||||
|
||||
LLJS_FROM_OBJ(AnnotationsNativeRootfs)
|
||||
{
|
||||
LLJS_FROM(mounts);
|
||||
}
|
||||
|
||||
LLJS_TO_OBJ(AnnotationsNativeRootfs)
|
||||
{
|
||||
LLJS_TO(mounts);
|
||||
}
|
||||
|
||||
struct Annotations {
|
||||
std::string container_root_path;
|
||||
tl::optional<AnnotationsOverlayfs> overlayfs;
|
||||
tl::optional<AnnotationsNativeRootfs> native;
|
||||
};
|
||||
|
||||
LLJS_FROM_OBJ(Annotations)
|
||||
{
|
||||
LLJS_FROM(container_root_path);
|
||||
LLJS_FROM_OPT(overlayfs);
|
||||
LLJS_FROM_OPT(native);
|
||||
}
|
||||
|
||||
LLJS_TO_OBJ(Annotations)
|
||||
{
|
||||
LLJS_TO(container_root_path);
|
||||
LLJS_TO(overlayfs);
|
||||
LLJS_TO(native);
|
||||
}
|
||||
|
||||
struct Runtime {
|
||||
std::string version;
|
||||
Root root;
|
||||
Process process;
|
||||
std::string hostname;
|
||||
Linux linux;
|
||||
tl::optional<std::vector<Mount>> mounts;
|
||||
tl::optional<Hooks> hooks;
|
||||
tl::optional<Annotations> annotations;
|
||||
};
|
||||
|
||||
inline void from_json(const nlohmann::json &j, Runtime &o)
|
||||
{
|
||||
o.version = j.at("ociVersion").get<std::string>();
|
||||
o.hostname = j.at("hostname").get<std::string>();
|
||||
LLJS_FROM(process);
|
||||
o.mounts = optional<decltype(o.mounts)::value_type>(j, "mounts");
|
||||
LLJS_FROM(linux);
|
||||
// maybe optional
|
||||
LLJS_FROM(root);
|
||||
o.hooks = optional<decltype(o.hooks)::value_type>(j, "hooks");
|
||||
LLJS_FROM_OPT(annotations);
|
||||
}
|
||||
|
||||
inline void to_json(nlohmann::json &j, const Runtime &o)
|
||||
{
|
||||
j["ociVersion"] = o.version;
|
||||
j["hostname"] = o.hostname;
|
||||
j["process"] = o.process;
|
||||
j["mounts"] = o.mounts;
|
||||
j["linux"] = o.linux;
|
||||
j["root"] = o.root;
|
||||
j["hooks"] = o.hooks;
|
||||
LLJS_TO(annotations);
|
||||
}
|
||||
|
||||
inline static Runtime fromFile(const std::string &filepath)
|
||||
{
|
||||
return util::json::fromFile(filepath).get<Runtime>();
|
||||
}
|
||||
|
||||
inline static Runtime fromString(const std::string &content)
|
||||
{
|
||||
return util::json::fromByteArray(content).get<Runtime>();
|
||||
}
|
||||
|
||||
} // namespace linglong
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_ */
|
Reference in New Issue
Block a user