Files
dde-application-manager/src/modules/util/oci_runtime.h
tsic404 d36a325b06 chore(CI): fix reuse
remove multi SPDX info

log:
2023-02-23 21:57:13 +08:00

1053 lines
29 KiB
C++

// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
//
// 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 <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QDebug>
#include <QVariant>
#include <QVector>
#include <QMap>
#include "util.h"
namespace linglong {
#undef linux
struct Root {
QString path;
// 删除 std::optional 和 宏定义
bool readonly;
};
inline void fromJson(const QByteArray &array, Root &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson root failed";
return;
}
QJsonObject obj = doc.object();
// readonly 可以不存在
if (!obj.contains("path")) {
return;
}
o.path = obj.value("path").toString();
if (obj.contains("readonly")) {
o.readonly = obj.value("readonly").toBool();
}
}
inline void toJson(QByteArray &array, const Root &o)
{
QJsonObject obj {
{"path", o.path},
{"readonly", o.readonly}
};
array = QJsonDocument(obj).toJson();
}
struct Process {
QList<QString> args;
QList<QString> env;
QString cwd;
};
inline void fromJson(const QByteArray &array, Process &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson process failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("args") || !obj.contains("env") || !obj.contains("cwd")) {
std::cout << "process json invalid format" << std::endl;
return;
}
for (auto arg : obj.value("args").toArray()) {
o.args.append(arg.toString());
}
for (auto env : obj.value("env").toArray()) {
o.env.append(env.toString());
}
o.cwd = obj.value("cwd").toString();
}
inline void toJson(QByteArray &array, const Process &o)
{
QJsonArray argsArray;
for (auto arg : o.args) {
argsArray.append(arg);
}
QJsonArray envsArray;
for (auto env : o.env) {
envsArray.append(env);
}
QJsonObject obj = {
{"args", argsArray},
{"env", envsArray},
{"cwd", o.cwd}
};
array = QJsonDocument(obj).toJson();
}
struct Mount {
enum Type {
Unknown,
Bind,
Proc,
Sysfs,
Devpts,
Mqueue,
Tmpfs,
Cgroup,
Cgroup2,
};
QString destination;
QString type;
QString source;
QList<QString> data;
Type fsType;
uint32_t flags = 0u;
};
inline void fromJson(const QByteArray &array, Mount &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson mount failed";
return;
}
QJsonObject obj = doc.object();
static QMap<QString, 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 QMap<QVariant, 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
};
if (!obj.contains("destination") || !obj.contains("type") || !obj.contains("source") \
|| !obj.contains("options")) {
std::cout << "mount json invalid format" << std::endl;
return;
}
o.destination = obj.value("destination").toString();
o.type = obj.value("type").toString();
o.fsType = fsTypes.find(o.type).value();
if (o.fsType == Mount::Bind) {
o.flags = MS_BIND;
}
o.source = obj.value("source").toString();
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 = obj.value("options").toArray().toVariantList();
for (auto const &opt : options) {
auto it = optionFlags.find(opt);
if (it != optionFlags.end()) {
if (it.value().clear) {
o.flags &= ~it.value().flag;
} else
o.flags |= it.value().flag;
} else {
o.data.push_back(opt.toString());
}
}
}
inline void toJson(QByteArray &array, const Mount &o)
{
QJsonArray dataArray;
for (auto const &data : o.data) {
dataArray.append(data);
}
QJsonObject obj = {
{"destination", o.destination},
{"source", o.source},
{"type", o.type},
{"options", dataArray},// FIXME: this data is not original options, some of them have been prased to flags.
};
array = QJsonDocument(obj).toJson();
}
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 fromJson(const QByteArray &array, Namespace &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson namespace failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("type")) {
std::cout << "namespace json invalid format" << std::endl;
return;
}
o.type = namespaceType.find(obj.value("type").toString().toStdString())->second;
}
inline void toJson(QByteArray &array, 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; });
QJsonObject obj = {
{"type", matchPair->second},
};
array = QJsonDocument(obj).toJson();
}
struct IDMap {
uint64_t containerID = 0u;
uint64_t hostID = 0u;
uint64_t size = 0u;
};
inline void fromJson(const QByteArray &array, IDMap &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson idmap failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("hostID") || !obj.contains("containerID") || !obj.contains("size")) {
std::cout << "idmap json invalid format" << std::endl;
return;
}
o.hostID = obj.value("hostID").toVariant().ULongLong;
o.containerID = obj.value("containerID").toVariant().ULongLong;
o.size = obj.value("size").toVariant().ULongLong;
}
inline void toJson(QByteArray &array, const IDMap &o)
{
QJsonObject obj = {
{"hostID", QString::number(o.hostID, 10)},
{"containerID", QString::number(o.containerID, 10)},
{"size", QString::number(o.size, 10)},
};
array = QJsonDocument(obj).toJson();
}
typedef QString SeccompAction;
typedef QString SeccompArch;
struct SyscallArg {
u_int index; // require
u_int64_t value; // require
u_int64_t valueTwo; // optional
QString op; // require
};
inline void fromJson(const QByteArray &array, SyscallArg &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson SyscallArg failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("index") || !obj.contains("value") \
|| !obj.contains("valueTwo") || !obj.contains("op")) {
qWarning() << "syscallarg json invalid format";
return;
}
o.index = obj.value("index").toVariant().UInt;
o.value = obj.value("value").toVariant().ULongLong;
o.valueTwo = obj.value("valueTwo").toVariant().ULongLong;
o.op = obj.value("op").toString();
}
inline void toJson(QByteArray &array, const SyscallArg &o)
{
QJsonObject obj = {
{"index", QString::number(o.index, 10)},
{"value", QString::number(o.value, 10)},
{"valueTwo", QString::number(o.valueTwo, 10)},
{"op", o.op},
};
array = QJsonDocument(obj).toJson();
}
struct Syscall {
QList<QString> names;
SeccompAction action;
QList<SyscallArg> args;
};
inline void fromJson(const QByteArray &array, Syscall &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Syscall failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("names") || !obj.contains("action") || !obj.contains("args")) {
std::cout << "syscall json invalid format" << std::endl;
return;
}
o.action = obj.value("action").toString();
for (auto const &name : obj.value("names").toArray()) {
o.names.append(name.toString());
}
QJsonValue argsValue = obj.take("args");
SyscallArg tmpArgs;
for (const auto &arg : argsValue.toArray()) {
fromJson(QJsonDocument(arg.toObject()).toJson(), tmpArgs);
o.args.append(tmpArgs);
}
}
inline void toJson(QByteArray &array, const Syscall &o)
{
QByteArray argsArray;
QJsonArray argsJsonArray;
for (const auto &arg : o.args) {
toJson(argsArray, arg);
argsJsonArray.append(QJsonDocument::fromJson(argsArray).array());
}
QByteArray namesArray;
QJsonArray namesJsonArray;
for (const auto &name : o.names) {
namesJsonArray.append(name);
}
QJsonObject obj = {
{ "names", namesJsonArray },
{ "action", o.action },
{ "args", argsJsonArray },
};
array = QJsonDocument(obj).toJson();
}
struct Seccomp {
SeccompAction defaultAction = "INVALID_ACTION";
QList<QString> architectures;
QList<Syscall> syscalls;
};
inline void fromJson(const QByteArray &array, Seccomp &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Seccomp failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("defaultAction") || !obj.contains("architectures") \
|| !obj.contains("syscalls")) {
qWarning() << "seccomp json invalid format";
return;
}
o.defaultAction = obj.value("defaultAction").toString();
for (auto const &arch : obj.value("architectures").toArray()) {
o.architectures.append(arch.toString());
}
Syscall syscallsArray;
for (auto const &syscall : obj.value("syscalls").toArray()) {
fromJson(QJsonDocument(syscall.toObject()).toJson(), syscallsArray);
o.syscalls.append(syscallsArray);
}
}
inline void toJson(QByteArray &array, const Seccomp &o)
{
QJsonArray syscallsJsonArray;
QByteArray syscallsByteArray;
for (auto const &syscall : o.syscalls) {
toJson(syscallsByteArray, syscall);
syscallsJsonArray.append(QJsonDocument::fromJson(syscallsByteArray).array());
}
QJsonArray archArray;
for (auto const &arch : o.architectures) {
archArray.append(arch);
}
QJsonObject obj = {
{ "defaultAction", o.defaultAction },
{ "architectures", archArray },
{ "syscalls", syscallsJsonArray },
};
array = QJsonDocument(obj).toJson();
}
// 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 fromJson(const QByteArray &array, ResourceMemory &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson ResourceMemory failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("limit") || !obj.contains("reservation") || !obj.contains("swap")) {
qWarning() << "resourceMemory json invalid format";
return;
}
o.limit = obj.value("limit").toVariant().toLongLong();
o.reservation = obj.value("reservation").toVariant().toLongLong();
o.swap = obj.value("swap").toVariant().toLongLong();
}
inline void toJson(QByteArray &array, const ResourceMemory &o)
{
QJsonObject obj = {
{"limit", static_cast<qint64>(o.limit)},
{"reservation", static_cast<qint64>(o.reservation)},
{"swap", static_cast<qint64>(o.swap)},
};
array = QJsonDocument(obj).toJson();
}
// 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 fromJson(const QByteArray &array, ResourceCPU &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson ResourceCPU failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("shares") || !obj.contains("quota") || !obj.contains("period")) {
qWarning() << "resourcecpu json invalid format";
return;
}
o.shares = obj.value("shares").toVariant().toULongLong();
o.quota = obj.value("quota").toVariant().toLongLong();
o.period = obj.value("period").toVariant().toULongLong();
}
inline void toJson(QByteArray &array, const ResourceCPU &o)
{
QJsonObject obj = {
{"shares", QString::number(o.shares, 10)},
{"quota", static_cast<qint64>(o.quota)},
{"period", QString::number(o.period, 10)},
};
array = QJsonDocument(obj).toJson();
}
struct Resources {
ResourceMemory memory;
ResourceCPU cpu;
};
inline void fromJson(const QByteArray &array, Resources &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Resources failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("cpu") || !obj.contains("memory")) {
qWarning() << "resources json invalid format";
return;
}
fromJson(QJsonDocument(obj.value("cpu").toObject()).toJson(), o.cpu);
fromJson(QJsonDocument(obj.value("memory").toObject()).toJson(), o.cpu);
}
inline void toJson(QByteArray &array, const Resources &o)
{
QByteArray cpuArray;
toJson(cpuArray, o.cpu);
QByteArray memoryArray;
toJson(memoryArray, o.memory);
QJsonObject obj = {
{"cpu", QJsonDocument::fromJson(cpuArray).array()},
{"memory", QJsonDocument::fromJson(memoryArray).array()},
};
array = QJsonDocument(obj).toJson();
}
struct Linux {
QList<Namespace> namespaces;
QList<IDMap> uidMappings;
QList<IDMap> gidMappings;
Seccomp seccomp;
QString cgroupsPath;
Resources resources;
};
inline void fromJson(const QByteArray &array, Linux &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Linux failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("namespaces") || !obj.contains("uidMappings") || !obj.contains("gidMappings") \
|| !obj.contains("cgroupsPath") || !obj.contains("resources")) {
qWarning() << "linux json invalid format";
return;
}
Namespace nameArray;
for (auto name : obj.take("namespaces").toArray()) {
fromJson(QJsonDocument(name.toObject()).toJson(), nameArray);
o.namespaces.append(nameArray);
}
{
IDMap uidMap;
for (auto uid : obj.take("uidMappings").toArray()) {
fromJson(QJsonDocument(uid.toObject()).toJson(), uidMap);
o.uidMappings.append(uidMap);
}
}
{
IDMap gidMap;
for (auto gid : obj.take("gidMappings").toArray()) {
fromJson(QJsonDocument(gid.toObject()).toJson(), gidMap);
o.gidMappings.append(gidMap);
}
}
o.cgroupsPath = obj.value("cgroupsPath").toString();
fromJson(QJsonDocument(obj.value("resources").toObject()).toJson(), o.resources);
if (obj.contains("seccomp")) {
fromJson(QJsonDocument(obj.value("seccomp").toObject()).toJson(), o.seccomp);
}
}
inline void toJson(QByteArray &array, const Linux &o)
{
QJsonArray nameSpacesJsonArray;
QByteArray nameSpacesByteArray;
for (auto const &nameSpace : o.namespaces) {
toJson(nameSpacesByteArray, nameSpace);
nameSpacesJsonArray.append(QJsonDocument::fromJson(nameSpacesByteArray).array());
}
QJsonArray uidMapsJsonArray;
QByteArray uidMapsByteArray;
for (auto const &uid : o.uidMappings) {
toJson(uidMapsByteArray, uid);
uidMapsJsonArray.append(QJsonDocument::fromJson(uidMapsByteArray).array());
}
QJsonArray gidMapsJsonArray;
QByteArray gidMapsByteArray;
for (auto const &gid : o.gidMappings) {
toJson(gidMapsByteArray, gid);
gidMapsJsonArray.append(QJsonDocument::fromJson(gidMapsByteArray).array());
}
QByteArray seccompArray;
toJson(seccompArray, o.seccomp);
QByteArray resourcesArray;
toJson(resourcesArray, o.resources);
QJsonObject obj = {
{"namespaces", nameSpacesJsonArray},
{"uidMappings", uidMapsJsonArray},
{"gidMappings", gidMapsJsonArray},
{"seccomp", QJsonDocument::fromJson(seccompArray).array()},
{"cgroupsPath", o.cgroupsPath},
{"resources", QJsonDocument::fromJson(resourcesArray).array()},
};
array = QJsonDocument(obj).toJson();
}
/*
"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 {
QString path;
QList<QString> args;
QList<QString> env;
};
inline void fromJson(const QByteArray &array, Hook &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Hook failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("path")) {
qWarning() << "hook json invalid format";
return;
}
o.path = obj.value("path").toString();
if (obj.contains("args")) {
for (auto const &arg : obj.value("args").toArray()) {
o.args.append(arg.toString());
}
}
if (obj.contains("env")) {
for (auto const &env : obj.value("env").toArray()) {
o.env.append(env.toString());
}
}
}
inline void toJson(QByteArray &array, const Hook &o)
{
QJsonArray argsArray;
for (auto const &arg : o.args) {
argsArray.append(arg);
}
QJsonArray envArray;
for (auto const &env : o.env) {
envArray.append(env);
}
QJsonObject obj = {
{"path", o.path},
{"args", argsArray},
{"env", envArray},
};
array = QJsonDocument(obj).toJson();
}
struct Hooks {
QList<Hook> prestart;
QList<Hook> poststart;
QList<Hook> poststop;
};
inline void fromJson(const QByteArray &array, Hooks &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Hooks failed";
return;
}
QJsonObject obj = doc.object();
Hook hook;
if (obj.contains("prestart")) {
for (auto prestart : obj.take("prestart").toArray()) {
fromJson(QJsonDocument(prestart.toObject()).toJson(), hook);
o.prestart.append(hook);
}
}
if (obj.contains("poststart")) {
for (auto poststart : obj.take("poststart").toArray()) {
fromJson(QJsonDocument(poststart.toObject()).toJson(), hook);
o.poststart.append(hook);
}
}
if (obj.contains("poststop")) {
for (auto poststop : obj.take("poststop").toArray()) {
fromJson(QJsonDocument(poststop.toObject()).toJson(), hook);
o.poststop.append(hook);
}
}
}
inline void toJson(QByteArray &array, const Hooks &o)
{
QJsonArray poststartJsonArray;
QByteArray poststartByteArray;
for (auto const &poststart : o.poststart) {
toJson(poststartByteArray, poststart);
poststartJsonArray.append(QJsonDocument::fromJson(poststartByteArray).array());
}
QJsonArray poststopJsonArray;
QByteArray poststopByteArray;
for (auto const &poststop : o.poststop) {
toJson(poststopByteArray, poststop);
poststopJsonArray.append(QJsonDocument::fromJson(poststopByteArray).array());
}
QJsonArray prestartJsonArray;
QByteArray prestartByteArray;
for (auto const &prestart : o.prestart) {
toJson(prestartByteArray, prestart);
prestartJsonArray.append(QJsonDocument::fromJson(prestartByteArray).array());
}
QJsonObject obj = {
{"prestart", prestartJsonArray},
{"poststart", poststartJsonArray},
{"poststop", poststopJsonArray},
};
array = QJsonDocument(obj).toJson();
}
struct AnnotationsOverlayfs {
QString lower_parent;
QString upper;
QString workdir;
QList<Mount> mounts;
};
inline void fromJson(const QByteArray &array, AnnotationsOverlayfs &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson AnnotationsOverlayfs failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("lower_parent") || !obj.contains("upper") \
|| !obj.contains("workdir") || !obj.contains("mounts")) {
qWarning() << "annotationsOverlayfs json invalid format";
return;
}
o.lower_parent = obj.value("lower_parent").toString();
o.upper = obj.value("upper").toString();
o.workdir = obj.value("workdir").toString();
Mount mount;
for (auto mountArray : obj.take("mounts").toArray()) {
fromJson(QJsonDocument(mountArray.toObject()).toJson(), mount);
o.mounts.append(mount);
}
}
inline void toJson(QByteArray &array, const AnnotationsOverlayfs &o)
{
QJsonArray MountsJsonArray;
QByteArray MountsByteArray;
for (auto const &mount : o.mounts) {
toJson(MountsByteArray, mount);
MountsJsonArray.append(QJsonDocument::fromJson(MountsByteArray).array());
}
QJsonObject obj = {
{"lower_parent", o.lower_parent},
{"upper", o.upper},
{"workdir", o.workdir},
{"mounts", MountsJsonArray},
};
array = QJsonDocument(obj).toJson();
}
struct AnnotationsNativeRootfs {
QList<Mount> mounts;
};
inline void fromJson(const QByteArray &array, AnnotationsNativeRootfs &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson AnnotationsNativeRootfs failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("mounts")) {
qWarning() << "annotationsNativeRootfs json invalid format";
return;
}
Mount mount;
for (auto uid : obj.take("mounts").toArray()) {
fromJson(QJsonDocument(uid.toObject()).toJson(), mount);
o.mounts.append(mount);
}
}
inline void toJson(QByteArray &array, const AnnotationsNativeRootfs &o)
{
QJsonArray mountsJsonArray;
QByteArray mountsByteArray;
for (auto const &mount : o.mounts) {
toJson(mountsByteArray, mount);
mountsJsonArray.append(QJsonDocument::fromJson(mountsByteArray).array());
}
QJsonObject obj = {
{"mounts", mountsJsonArray},
};
array = QJsonDocument(obj).toJson();
}
struct Annotations {
QString container_root_path;
AnnotationsOverlayfs overlayfs;
AnnotationsNativeRootfs native;
};
inline void fromJson(const QByteArray &array, Annotations &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Linux failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("container_root_path")) {
qWarning() << "annotations json invalid format";
return;
}
o.container_root_path = obj.value("container_root_path").toString();
if (obj.contains("overlayfs")) {
fromJson(QJsonDocument(obj.value("overlayfs").toObject()).toJson(), o.overlayfs);
}
if (obj.contains("native")) {
fromJson(QJsonDocument(obj.value("native").toObject()).toJson(), o.native);
}
}
inline void toJson(QByteArray &array, const Annotations &o)
{
QByteArray overlayfsArray;
toJson(overlayfsArray, o.overlayfs);
QByteArray nativeArray;
toJson(nativeArray, o.native);
QJsonObject obj = {
{"overlayfs", QJsonDocument::fromJson(overlayfsArray).array()},
{"native", QJsonDocument::fromJson(nativeArray).array()},
{"container_root_path", o.container_root_path}
};
array = QJsonDocument(obj).toJson();
}
struct Runtime {
QString version;
Root root;
Process process;
QString hostname;
Linux linux;
QList<Mount> mounts;
Hooks hooks;
Annotations annotations;
};
inline void fromJson(const QByteArray &array, Runtime &o)
{
QJsonDocument doc = QJsonDocument::fromJson(array);
if (!doc.isObject()) {
qWarning() << "fromJson Runtime failed";
return;
}
QJsonObject obj = doc.object();
if (!obj.contains("version") || !obj.contains("root") || !obj.contains("process") \
|| !obj.contains("hostname") || !obj.contains("linux")) {
qWarning() << "runtime json invalid format";
return;
}
o.version = obj.value("version").toString();
o.hostname = obj.value("hostname").toString();
fromJson(QJsonDocument(obj.value("root").toObject()).toJson(), o.root);
fromJson(QJsonDocument(obj.value("process").toObject()).toJson(), o.process);
fromJson(QJsonDocument(obj.value("linux").toObject()).toJson(), o.linux);
// mounts hooks annotations 可不存在
if (!obj.contains("mounts") || !obj.contains("hooks") || !obj.contains("annotations")) {
return;
}
fromJson(QJsonDocument(obj.value("hooks").toObject()).toJson(), o.hooks);
fromJson(QJsonDocument(obj.value("annotations").toObject()).toJson(), o.annotations);
Mount mount;
for (auto uid : obj.take("mounts").toArray()) {
fromJson(QJsonDocument(uid.toObject()).toJson(), mount);
o.mounts.append(mount);
}
}
inline void toJson(QByteArray &array, const Runtime &o)
{
QByteArray rootArray;
QByteArray processArray;
QByteArray linuxArray;
QByteArray hooksArray;
QByteArray annotationsArray;
toJson(rootArray, o.root);
toJson(processArray, o.process);
toJson(linuxArray, o.linux);
toJson(hooksArray, o.hooks);
toJson(annotationsArray, o.annotations);
QJsonArray MountsJsonArray;
QByteArray MountsByteArray;
for (auto const &mount : o.mounts) {
toJson(MountsByteArray, mount);
MountsJsonArray.append(QJsonDocument::fromJson(MountsByteArray).array());
}
QJsonObject obj = {
{"version", o.version},
{"root", QJsonDocument::fromJson(rootArray).array()},
{"process", QJsonDocument::fromJson(processArray).array()},
{"hostname", o.hostname},
{"linux", QJsonDocument::fromJson(linuxArray).array()},
{"hooks", QJsonDocument::fromJson(hooksArray).array()},
{"annotations", QJsonDocument::fromJson(annotationsArray).array()},
{"mounts", MountsJsonArray},
};
array = QJsonDocument(obj).toJson();
}
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_ */