diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-04-11 17:24:08 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-04-12 13:43:33 +0200 |
commit | d94c2b06f9800d635f3cb05b4a6c67145aa1ba09 (patch) | |
tree | 35bbd746d0e8ec646c66e39b63d9a15d9824412b /src/machine | |
parent | d5bd92bbbe578d96b3905832cd3ccdb9249e620c (diff) |
machinectl: add new "machinectl clean" command
This new command removes all, or all hidden container images that have been
downloaded.
Diffstat (limited to 'src/machine')
-rw-r--r-- | src/machine/machinectl.c | 46 | ||||
-rw-r--r-- | src/machine/machined-dbus.c | 88 |
2 files changed, 134 insertions, 0 deletions
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 1d3264a1de..35177aa29e 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2338,6 +2338,50 @@ static int set_limit(int argc, char *argv[], void *userdata) { return 0; } +static int clean_images(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + uint64_t usage, total = 0; + char fb[FORMAT_BYTES_MAX]; + sd_bus *bus = userdata; + const char *name; + unsigned c = 0; + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "CleanPool", + &error, + &reply, + "s", arg_all ? "all" : "hidden"); + if (r < 0) + return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r)); + + r = sd_bus_message_enter_container(reply, 'a', "(st)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) { + log_info("Removed image '%s'. Freed exclusive disk space: %s", + name, format_bytes(fb, sizeof(fb), usage)); + + total += usage; + c++; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + log_info("Removed %u images in total. Total freed exclusive disk space %s.", + c, format_bytes(fb, sizeof(fb), total)); + + return 0; +} + static int help(int argc, char *argv[], void *userdata) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" @@ -2396,6 +2440,7 @@ static int help(int argc, char *argv[], void *userdata) { " read-only NAME [BOOL] Mark or unmark image read-only\n" " remove NAME... Remove an image\n" " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n" + " clean Remove hidden (or all) images\n" "Image Transfer Commands:\n" " pull-tar URL [NAME] Download a TAR container image\n" " pull-raw URL [NAME] Download a RAW container or VM image\n" @@ -2635,6 +2680,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "list-transfers", VERB_ANY, 1, 0, list_transfers }, { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, { "set-limit", 2, 3, 0, set_limit }, + { "clean", VERB_ANY, 1, 0, clean_images }, {} }; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 20894433e7..c9639c3cf2 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -802,6 +802,93 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata, return bus_image_method_mark_read_only(message, i, error); } +static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) { + enum { + REMOVE_ALL, + REMOVE_HIDDEN, + } mode; + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(image_hashmap_freep) Hashmap *images = NULL; + Manager *m = userdata; + Image *image; + const char *mm; + Iterator i; + int r; + + assert(message); + + r = sd_bus_message_read(message, "s", &mm); + if (r < 0) + return r; + + if (streq(mm, "all")) + mode = REMOVE_ALL; + else if (streq(mm, "hidden")) + mode = REMOVE_HIDDEN; + else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm); + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-machines", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + images = hashmap_new(&string_hash_ops); + if (!images) + return -ENOMEM; + + r = image_discover(images); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(image, images, i) { + + /* We can't remove vendor images (i.e. those in /usr) */ + if (IMAGE_IS_VENDOR(image)) + continue; + + if (IMAGE_IS_HOST(image)) + continue; + + if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image)) + continue; + + r = image_remove(image); + if (r == -EBUSY) /* keep images that are currently being used. */ + continue; + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name); + + r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; uint64_t limit; @@ -1144,6 +1231,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED), |