mirror of
https://github.com/systemd/systemd.git
synced 2025-03-09 12:58:26 +03:00
machined,machinectl: add calls for changing container/VM quotas
This commit is contained in:
parent
950c07d421
commit
d6ce17c7f0
@ -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>
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"/>
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user