core: adding CGroup runtime for io.systemd.Unit.List
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "json-util.h"
|
||||
#include "in-addr-prefix-util.h"
|
||||
#include "ip-protocol-list.h"
|
||||
#include "path-util.h"
|
||||
#include "set.h"
|
||||
#include "unit.h"
|
||||
#include "varlink-cgroup.h"
|
||||
@@ -351,3 +352,261 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void
|
||||
/* Others */
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("CoredumpReceive", c->coredump_receive));
|
||||
}
|
||||
|
||||
static int memory_accounting_metric_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
CGroupMemoryAccountingMetric metric;
|
||||
uint64_t value;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
metric = cgroup_memory_accounting_metric_from_string(name);
|
||||
assert(metric >= 0);
|
||||
|
||||
r = unit_get_memory_accounting(u, metric, &value);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
|
||||
|
||||
if (value == UINT64_MAX)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, value);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_available_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
uint64_t value;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
r = unit_get_memory_available(u, &value);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get value of available memory: %m");
|
||||
|
||||
if (value == UINT64_MAX)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, value);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int effective_limit_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
CGroupLimitType type;
|
||||
uint64_t value;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
type = cgroup_effective_limit_type_from_string(name);
|
||||
assert(type >= 0);
|
||||
|
||||
r = unit_get_effective_limit(u, type, &value);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
|
||||
|
||||
if (value == UINT64_MAX) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, value);
|
||||
}
|
||||
|
||||
static int cpu_usage_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
nsec_t ns;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
r = unit_get_cpu_usage(u, &ns);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get cpu usage: %m");
|
||||
|
||||
if (ns == NSEC_INFINITY)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, ns);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int effective_cpuset_build_json(sd_json_variant **ret, const char *name, void *userdata, const char *cpuset_name) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
_cleanup_(cpu_set_reset) CPUSet cpus = {};
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
assert(cpuset_name);
|
||||
|
||||
r = unit_get_cpuset(u, &cpus, cpuset_name);
|
||||
if (r == -ENODATA) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get cpu set '%s': %m", cpuset_name);
|
||||
|
||||
return cpu_set_build_json(ret, name, &cpus);
|
||||
}
|
||||
|
||||
static inline int effective_cpus_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
return effective_cpuset_build_json(ret, name, userdata, "cpuset.cpus.effective");
|
||||
}
|
||||
|
||||
static inline int effective_mems_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
return effective_cpuset_build_json(ret, name, userdata, "cpuset.mems.effective");
|
||||
}
|
||||
|
||||
static int tasks_current_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
uint64_t cn;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
r = unit_get_tasks_current(u, &cn);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get count of current tasks: %m");
|
||||
|
||||
if (cn == UINT64_MAX)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, cn);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ip_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
CGroupIPAccountingMetric metric;
|
||||
uint64_t value;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
metric = cgroup_ip_accounting_metric_from_string(name);
|
||||
assert(metric >= 0);
|
||||
|
||||
r = unit_get_ip_accounting(u, metric, &value);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
|
||||
|
||||
if (value == UINT64_MAX)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, value);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_io_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
CGroupIOAccountingMetric metric;
|
||||
uint64_t value;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
metric = cgroup_io_accounting_metric_from_string(name);
|
||||
assert(metric >= 0);
|
||||
|
||||
r = unit_get_io_accounting(u, metric, &value);
|
||||
if (r == -ENODATA)
|
||||
goto empty;
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
|
||||
|
||||
if (value == UINT64_MAX)
|
||||
goto empty;
|
||||
|
||||
return sd_json_variant_new_unsigned(ret, value);
|
||||
|
||||
empty:
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_cgroup_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
|
||||
assert(ret);
|
||||
assert(name);
|
||||
|
||||
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||
if (!crt) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sd_json_buildo(
|
||||
ret,
|
||||
|
||||
/* ID */
|
||||
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ID", crt->cgroup_id),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", crt->cgroup_path ? empty_to_root(crt->cgroup_path) : NULL),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("Slice", unit_slice_name(u)),
|
||||
|
||||
/* Memory */
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryCurrent", memory_accounting_metric_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryPeak", memory_accounting_metric_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapCurrent", memory_accounting_metric_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapPeak", memory_accounting_metric_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryZSwapCurrent", memory_accounting_metric_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryAvailable", memory_available_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryMax", effective_limit_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryHigh", effective_limit_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryNodes", effective_mems_build_json, u),
|
||||
|
||||
/* CPU */
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("CPUUsageNSec", cpu_usage_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveCPUs", effective_cpus_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("TasksCurrent", tasks_current_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveTasksMax", effective_limit_build_json, u),
|
||||
|
||||
/* IP */
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressBytes", get_ip_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressPackets", get_ip_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressBytes", get_ip_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressPackets", get_ip_counter_build_json, u),
|
||||
|
||||
/* IO */
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadBytes", get_io_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadOperations", get_io_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteBytes", get_io_counter_build_json, u),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteOperations", get_io_counter_build_json, u));
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
#include "forward.h"
|
||||
|
||||
int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void *userdata);
|
||||
int unit_cgroup_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata);
|
||||
|
||||
@@ -300,7 +300,8 @@ static int unit_runtime_build_json(sd_json_variant **ret, const char *name, void
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(u->invocation_id), "InvocationID", SD_JSON_BUILD_UUID(u->invocation_id)),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("Markers", markers_build_json, &u->markers),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("ActivationDetails", activation_details_build_json, u->activation_details),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DebugInvocation", u->debug_invocation));
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("DebugInvocation", u->debug_invocation),
|
||||
JSON_BUILD_PAIR_CALLBACK_NON_NULL("CGroup", unit_cgroup_runtime_build_json, u));
|
||||
}
|
||||
|
||||
static int list_unit_one(sd_varlink *link, Unit *unit, bool more) {
|
||||
|
||||
@@ -393,6 +393,67 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
SD_VARLINK_FIELD_COMMENT("Trigger unit name"),
|
||||
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
CGroupRuntime,
|
||||
|
||||
/* ID */
|
||||
SD_VARLINK_FIELD_COMMENT("ID of the CGroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path of the CGroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(Path, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Slice of the CGroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(Slice, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
|
||||
/* Memory */
|
||||
SD_VARLINK_FIELD_COMMENT("The current amount of memory used by the cgroup, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(MemoryCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The peak amount of memory used by the cgroup since its creation, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(MemoryPeak, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The current amount of swap space used by the cgroup, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(MemorySwapCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The peak amount of swap space used by the cgroup since its creation, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(MemorySwapPeak, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The current amount of zswap space used by the cgroup, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(MemoryZSwapCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The available memory for the cgroup, in bytes."),
|
||||
SD_VARLINK_DEFINE_FIELD(MemoryAvailable, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The effective maximum amount of memory allowed for the cgroup, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryMax, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The effective high watermark for memory usage by the cgroup, in bytes"),
|
||||
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryHigh, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Memory NUMA nodes that the cgroup is allowed to use"),
|
||||
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryNodes, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
|
||||
|
||||
/* CPU */
|
||||
SD_VARLINK_FIELD_COMMENT("The total CPU usage time in nanoseconds (ns) for the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(CPUUsageNSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("NUMA nodes that the cgroup is allowed to use"),
|
||||
SD_VARLINK_DEFINE_FIELD(EffectiveCPUs, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The current number of tasks (i.e., processes or threads) running within the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(TasksCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The maximum number of tasks that the cgroup is allowed to run concurrently"),
|
||||
SD_VARLINK_DEFINE_FIELD(EffectiveTasksMax, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
|
||||
/* IP */
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of bytes received by the cgroup's IP stack"),
|
||||
SD_VARLINK_DEFINE_FIELD(IPIngressBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of incoming packets received by the cgroup's IP stack"),
|
||||
SD_VARLINK_DEFINE_FIELD(IPIngressPackets, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("iThe total number of bytes sent by the cgroup's IP stack"),
|
||||
SD_VARLINK_DEFINE_FIELD(IPEgressBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of outgoing packets sent by the cgroup's IP stack"),
|
||||
SD_VARLINK_DEFINE_FIELD(IPEgressPackets, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
|
||||
/* IO */
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of bytes read from block devices by the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(IOReadBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of read operations performed on block devices by the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(IOReadOperations, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of bytes written to block devices by the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(IOWriteBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The total number of write operations performed on block devices by the cgroup"),
|
||||
SD_VARLINK_DEFINE_FIELD(IOWriteOperations, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
||||
|
||||
static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
UnitRuntime,
|
||||
SD_VARLINK_FIELD_COMMENT("If not empty, the field contains the name of another unit that this unit follows in state"),
|
||||
@@ -450,7 +511,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
SD_VARLINK_FIELD_COMMENT("Provides details about why a unit was activated"),
|
||||
SD_VARLINK_DEFINE_FIELD_BY_TYPE(ActivationDetails, ActivationDetails, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("When true, logs about this unit will be at debug level regardless of other log level settings"),
|
||||
SD_VARLINK_DEFINE_FIELD(DebugInvocation, SD_VARLINK_BOOL, 0));
|
||||
SD_VARLINK_DEFINE_FIELD(DebugInvocation, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("The cgroup runtime of the unit"),
|
||||
SD_VARLINK_DEFINE_FIELD_BY_TYPE(CGroup, CGroupRuntime, SD_VARLINK_NULLABLE));
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(NoSuchUnit);
|
||||
|
||||
@@ -496,5 +559,7 @@ SD_VARLINK_DEFINE_INTERFACE(
|
||||
&vl_type_CGroupDeviceAllow,
|
||||
SD_VARLINK_SYMBOL_COMMENT("CGroup context of a unit"),
|
||||
&vl_type_CGroupContext,
|
||||
SD_VARLINK_SYMBOL_COMMENT("CGroup runtime of a unit"),
|
||||
&vl_type_CGroupRuntime,
|
||||
SD_VARLINK_SYMBOL_COMMENT("No matching unit found"),
|
||||
&vl_error_NoSuchUnit);
|
||||
|
||||
Reference in New Issue
Block a user