machined: optionally, allow registration of pre-existing units (scopes

or services) as machine with machined
This commit is contained in:
Lennart Poettering
2014-02-11 17:16:08 +01:00
parent 2d2ebd6b8f
commit 89f7c8465c
9 changed files with 224 additions and 88 deletions
+2 -1
View File
@@ -132,7 +132,8 @@ const sd_bus_vtable machine_vtable[] = {
SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, scope), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+41 -16
View File
@@ -76,9 +76,9 @@ void machine_free(Machine *m) {
if (m->in_gc_queue)
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
if (m->scope) {
hashmap_remove(m->manager->machine_units, m->scope);
free(m->scope);
if (m->unit) {
hashmap_remove(m->manager->machine_units, m->unit);
free(m->unit);
}
free(m->scope_job);
@@ -123,8 +123,8 @@ int machine_save(Machine *m) {
"NAME=%s\n",
m->name);
if (m->scope)
fprintf(f, "SCOPE=%s\n", m->scope);
if (m->unit)
fprintf(f, "SCOPE=%s\n", m->unit); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
if (m->scope_job)
fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
@@ -159,6 +159,16 @@ int machine_save(Machine *m) {
unlink(temp_path);
}
if (m->unit) {
char *sl;
/* Create a symlink from the unit name to the machine
* name, so that we can quickly find the machine for
* each given unit */
sl = strappenda("/run/systemd/machines/unit:", m->unit);
symlink(m->name, sl);
}
finish:
if (r < 0)
log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r));
@@ -166,6 +176,21 @@ finish:
return r;
}
static void machine_unlink(Machine *m) {
assert(m);
if (m->unit) {
char *sl;
sl = strappenda("/run/systemd/machines/unit:", m->unit);
unlink(sl);
}
if (m->state_file)
unlink(m->state_file);
}
int machine_load(Machine *m) {
_cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
int r;
@@ -173,7 +198,7 @@ int machine_load(Machine *m) {
assert(m);
r = parse_env_file(m->state_file, NEWLINE,
"SCOPE", &m->scope,
"SCOPE", &m->unit,
"SCOPE_JOB", &m->scope_job,
"SERVICE", &m->service,
"ROOT", &m->root_directory,
@@ -225,7 +250,7 @@ static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_er
assert(m);
if (!m->scope) {
if (!m->unit) {
_cleanup_free_ char *escaped = NULL;
char *scope, *description, *job;
@@ -245,15 +270,15 @@ static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_er
free(scope);
return r;
} else {
m->scope = scope;
m->unit = scope;
free(m->scope_job);
m->scope_job = job;
}
}
if (m->scope)
hashmap_put(m->manager->machine_units, m->scope, m);
if (m->unit)
hashmap_put(m->manager->machine_units, m->unit, m);
return r;
}
@@ -302,10 +327,10 @@ static int machine_stop_scope(Machine *m) {
assert(m);
if (!m->scope)
if (!m->unit)
return 0;
r = manager_stop_unit(m->manager, m->scope, &error, &job);
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0) {
log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
return r;
@@ -334,7 +359,7 @@ int machine_stop(Machine *m) {
if (k < 0)
r = k;
unlink(m->state_file);
machine_unlink(m);
machine_add_to_gc_queue(m);
if (m->started)
@@ -354,7 +379,7 @@ bool machine_check_gc(Machine *m, bool drop_not_started) {
if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
return true;
if (m->scope && manager_unit_is_active(m->manager, m->scope))
if (m->unit && manager_unit_is_active(m->manager, m->unit))
return true;
return false;
@@ -382,10 +407,10 @@ MachineState machine_get_state(Machine *s) {
int machine_kill(Machine *m, KillWho who, int signo) {
assert(m);
if (!m->scope)
if (!m->unit)
return -ESRCH;
return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
return manager_kill_unit(m->manager, m->unit, who, signo, NULL);
}
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
+1 -1
View File
@@ -63,7 +63,7 @@ struct Machine {
char *service;
char *root_directory;
char *scope;
char *unit;
char *scope_job;
pid_t leader;
+8 -8
View File
@@ -107,7 +107,7 @@ static int list_machines(sd_bus *bus, char **args, unsigned n) {
return 0;
}
static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL;
@@ -129,7 +129,7 @@ static int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Scope",
endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
"ControlGroup",
&error,
&reply,
@@ -168,7 +168,7 @@ typedef struct MachineStatusInfo {
sd_id128_t id;
char *class;
char *service;
char *scope;
char *unit;
char *root_directory;
pid_t leader;
usec_t timestamp;
@@ -219,9 +219,9 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
if (i->root_directory)
printf("\t Root: %s\n", i->root_directory);
if (i->scope) {
printf("\t Unit: %s\n", i->scope);
show_scope_cgroup(bus, i->scope, i->leader);
if (i->unit) {
printf("\t Unit: %s\n", i->unit);
show_unit_cgroup(bus, i->unit, i->leader);
}
}
@@ -231,7 +231,7 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
{ "Scope", "s", NULL, offsetof(MachineStatusInfo, scope) },
{ "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp) },
@@ -264,7 +264,7 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
free(info.name);
free(info.class);
free(info.service);
free(info.scope);
free(info.unit);
free(info.root_directory);
return r;
+62 -13
View File
@@ -169,9 +169,8 @@ static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *user
return sd_bus_send(bus, reply, NULL);
}
static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
const char *name, *service, *class, *root_directory;
Manager *manager = userdata;
MachineClass c;
uint32_t leader;
sd_id128_t id;
@@ -180,9 +179,9 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
size_t n;
int r;
assert(bus);
assert(message);
assert(manager);
assert(message);
assert(_m);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
@@ -218,10 +217,6 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
if (!isempty(root_directory) && !path_is_absolute(root_directory))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
r = sd_bus_message_enter_container(message, 'a', "(sv)");
if (r < 0)
return r;
if (leader == 0) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
@@ -263,17 +258,70 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
}
}
r = machine_start(m, message, error);
if (r < 0)
goto fail;
m->create_message = sd_bus_message_ref(message);
*_m = m;
return 1;
fail:
machine_add_to_gc_queue(m);
return r;
}
static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
Machine *m = NULL;
int r;
r = method_create_or_register_machine(manager, message, &m, error);
if (r < 0)
return r;
r = sd_bus_message_enter_container(message, 'a', "(sv)");
if (r < 0)
goto fail;
r = machine_start(m, message, error);
if (r < 0)
goto fail;
m->create_message = sd_bus_message_ref(message);
return 1;
fail:
machine_add_to_gc_queue(m);
return r;
}
static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
_cleanup_free_ char *p = NULL;
Machine *m = NULL;
int r;
r = method_create_or_register_machine(manager, message, &m, error);
if (r < 0)
return r;
r = cg_pid_get_unit(m->leader, &m->unit);
if (r < 0) {
r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
goto fail;
}
r = machine_start(m, NULL, error);
if (r < 0)
goto fail;
p = machine_bus_path(m);
if (!p) {
r = -ENOMEM;
goto fail;
}
return sd_bus_reply_method_return(message, "o", p);
fail:
machine_add_to_gc_queue(m);
return r;
}
@@ -347,6 +395,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_SIGNAL("MachineNew", "so", 0),