machined,machinectl: add calls for changing container/VM quotas

This commit is contained in:
Lennart Poettering 2015-02-24 23:50:37 +01:00
parent 950c07d421
commit d6ce17c7f0
10 changed files with 226 additions and 6 deletions

View File

@ -469,7 +469,7 @@
<varlistentry>
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
<listitem><para>Clones a container or disk image. The
<listitem><para>Clones a container or VM image. The
arguments specify the name of the image to clone and the name
of the newly cloned image. Note that plain directory container
images are cloned into subvolume images with this command.
@ -481,7 +481,7 @@
<varlistentry>
<term><command>rename</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
<listitem><para>Renames a container or disk image. The
<listitem><para>Renames a container or VM image. The
arguments specify the name of the image to rename and the new
name of the image.</para></listitem>
</varlistentry>
@ -489,22 +489,37 @@
<varlistentry>
<term><command>read-only</command> <replaceable>NAME</replaceable> [<replaceable>BOOL</replaceable>]</term>
<listitem><para>Marks or (unmarks) a container or disk image
<listitem><para>Marks or (unmarks) a container or VM image
read-only. Takes a VM or container image name, followed by a
boolean as arguments. If the boolean is omitted, positive is
implied, i.e. the image is marked read-only.</para></listitem>
</varlistentry>
<varlistentry>
<term><command>remove</command> <replaceable>NAME</replaceable>...</term>
<listitem><para>Removes one or more container or disk images.
<listitem><para>Removes one or more container or VM images.
The special image <literal>.host</literal>, which refers to
the host's own directory tree may not be
removed.</para></listitem>
</varlistentry>
<varlistentry>
<term><command>set-limit</command> [<replaceable>NAME</replaceable>] <replaceable>BYTES</replaceable></term>
<listitem><para>Sets the maximum size in bytes a specific
container or VM image, or all images may grow up to
(quota). Takes either one or two parameters. The first,
optional parameter refers to a container or VM image name. If
specified the size limit of the specified images is
changed. If omitted the overall size limit of the sum of all
images stored locally is changed. The final argument specifies
the size limit in bytes, possibly suffixed by the usual K, M,
G, T units. If the size limit shall be disabled, specify
<literal>-</literal> as size. This operation is currently only
supported on btrfs subvolume images.</para></listitem>
</varlistentry>
</variablelist></refsect2>
<refsect2><title>Image Transfer Commands</title><variablelist>

View File

@ -182,6 +182,44 @@ int bus_image_method_mark_read_only(
return sd_bus_reply_method_return(message, NULL);
}
int bus_image_method_set_limit(
sd_bus *bus,
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
Image *image = userdata;
Manager *m = image->userdata;
uint64_t limit;
int r;
assert(bus);
assert(message);
r = sd_bus_message_read(message, "t", &limit);
if (r < 0)
return r;
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
"org.freedesktop.machine1.manage-images",
false,
UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
r = image_set_limit(image, limit);
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}
const sd_bus_vtable image_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
@ -198,6 +236,7 @@ const sd_bus_vtable image_vtable[] = {
SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};

View File

@ -34,3 +34,4 @@ int bus_image_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata
int bus_image_method_rename(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_image_method_clone(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_image_method_mark_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_image_method_set_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);

View File

@ -1961,6 +1961,56 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) {
return 0;
}
static int set_limit(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
uint64_t limit;
int r;
if (streq(argv[argc-1], "-"))
limit = (uint64_t) -1;
else {
off_t off;
r = parse_size(argv[argc-1], 1024, &off);
if (r < 0)
return log_error("Failed to parse size: %s", argv[argc-1]);
limit = (uint64_t) off;
}
if (argc > 2)
/* With two arguments changes the quota limit of the
* specified image */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetImageLimit",
&error,
NULL,
"st", argv[1], limit);
else
/* With one argument changes the pool quota limit */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetPoolLimit",
&error,
NULL,
"t", limit);
if (r < 0) {
log_error("Could not set limit: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@ -2012,7 +2062,8 @@ static int help(int argc, char *argv[], void *userdata) {
" clone NAME NAME Clone an image\n"
" rename NAME NAME Rename an image\n"
" read-only NAME [BOOL] Mark or unmark image read-only\n"
" remove NAME... Remove an image\n\n"
" remove NAME... Remove an image\n"
" set-limit [NAME] BYTES Set image size limit (quota)\n\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"
@ -2221,6 +2272,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "pull-dkr", 2, 3, 0, pull_dkr },
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
{ "set-limit", 2, 3, 0, set_limit },
{}
};

View File

@ -776,6 +776,61 @@ static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, voi
return bus_image_method_mark_read_only(bus, message, i, error);
}
static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint64_t limit;
int r;
assert(bus);
r = sd_bus_message_read(message, "t", &limit);
if (r < 0)
return r;
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
"org.freedesktop.machine1.manage-machines",
false,
UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
r = btrfs_quota_limit("/var/lib/machines", limit);
if (r == -ENOTTY)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
else if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
return sd_bus_reply_method_return(message, NULL);
}
static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image *i = NULL;
const char *name;
int r;
assert(bus);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
if (!image_name_is_valid(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
r = image_find(name, &i);
if (r < 0)
return r;
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
i->userdata = userdata;
return bus_image_method_set_limit(bus, message, i, error);
}
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
@ -803,6 +858,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
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_SIGNAL("MachineNew", "so", 0),
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
SD_BUS_VTABLE_END

View File

@ -104,6 +104,14 @@
send_interface="org.freedesktop.machine1.Manager"
send_member="MarkImageReadOnly"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager"
send_member="SetPoolLimit"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager"
send_member="SetImageLimit"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Machine"
send_member="GetAddresses"/>
@ -148,6 +156,10 @@
send_interface="org.freedesktop.machine1.Image"
send_member="Clone"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Image"
send_member="SetLimit"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Image"
send_member="MarkReadOnly"/>

View File

@ -669,3 +669,29 @@ int btrfs_quota_enable(const char *path, bool b) {
return btrfs_quota_enable_fd(fd, b);
}
int btrfs_quota_limit_fd(int fd, uint64_t referred_max) {
struct btrfs_ioctl_qgroup_limit_args args = {
.lim.max_rfer =
referred_max == (uint64_t) -1 ? 0 :
referred_max == 0 ? 1 : referred_max,
.lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
};
assert(fd >= 0);
if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
return -errno;
return 0;
}
int btrfs_quota_limit(const char *path, uint64_t referred_max) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
return -errno;
return btrfs_quota_limit_fd(fd, referred_max);
}

View File

@ -67,3 +67,6 @@ int btrfs_defrag(const char *p);
int btrfs_quota_enable_fd(int fd, bool b);
int btrfs_quota_enable(const char *path, bool b);
int btrfs_quota_limit_fd(int fd, uint64_t referred_max);
int btrfs_quota_limit(const char *path, uint64_t referred_max);

View File

@ -613,6 +613,19 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
return 0;
}
int image_set_limit(Image *i, uint64_t referred_max) {
assert(i);
if (path_equal(i->path, "/") ||
path_startswith(i->path, "/usr"))
return -EROFS;
if (i->type != IMAGE_SUBVOLUME)
return -ENOTSUP;
return btrfs_quota_limit(i->path, referred_max);
}
int image_name_lock(const char *name, int operation, LockFile *ret) {
const char *p;

View File

@ -70,3 +70,5 @@ bool image_name_is_valid(const char *s) _pure_;
int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
int image_name_lock(const char *name, int operation, LockFile *ret);
int image_set_limit(Image *i, uint64_t referred_max);