mirror of
https://github.com/systemd/systemd.git
synced 2025-07-30 23:42:23 +03:00
machined,machinectl: add calls for changing container/VM quotas
This commit is contained in:
@ -469,7 +469,7 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
|
<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
|
arguments specify the name of the image to clone and the name
|
||||||
of the newly cloned image. Note that plain directory container
|
of the newly cloned image. Note that plain directory container
|
||||||
images are cloned into subvolume images with this command.
|
images are cloned into subvolume images with this command.
|
||||||
@ -481,7 +481,7 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>rename</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
|
<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
|
arguments specify the name of the image to rename and the new
|
||||||
name of the image.</para></listitem>
|
name of the image.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -489,22 +489,37 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>read-only</command> <replaceable>NAME</replaceable> [<replaceable>BOOL</replaceable>]</term>
|
<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
|
read-only. Takes a VM or container image name, followed by a
|
||||||
boolean as arguments. If the boolean is omitted, positive is
|
boolean as arguments. If the boolean is omitted, positive is
|
||||||
implied, i.e. the image is marked read-only.</para></listitem>
|
implied, i.e. the image is marked read-only.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><command>remove</command> <replaceable>NAME</replaceable>...</term>
|
<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 special image <literal>.host</literal>, which refers to
|
||||||
the host's own directory tree may not be
|
the host's own directory tree may not be
|
||||||
removed.</para></listitem>
|
removed.</para></listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist></refsect2>
|
||||||
|
|
||||||
<refsect2><title>Image Transfer Commands</title><variablelist>
|
<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);
|
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[] = {
|
const sd_bus_vtable image_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 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("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("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("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
|
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_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_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_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;
|
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) {
|
static int help(int argc, char *argv[], void *userdata) {
|
||||||
|
|
||||||
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
|
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"
|
" clone NAME NAME Clone an image\n"
|
||||||
" rename NAME NAME Rename an image\n"
|
" rename NAME NAME Rename an image\n"
|
||||||
" read-only NAME [BOOL] Mark or unmark image read-only\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"
|
"Image Transfer Commands:\n"
|
||||||
" pull-tar URL [NAME] Download a TAR container image\n"
|
" pull-tar URL [NAME] Download a TAR container image\n"
|
||||||
" pull-raw URL [NAME] Download a RAW container or VM 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 },
|
{ "pull-dkr", 2, 3, 0, pull_dkr },
|
||||||
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
|
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
|
||||||
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
|
{ "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);
|
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[] = {
|
const sd_bus_vtable manager_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 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("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("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("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("MachineNew", "so", 0),
|
||||||
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
|
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
|
@ -104,6 +104,14 @@
|
|||||||
send_interface="org.freedesktop.machine1.Manager"
|
send_interface="org.freedesktop.machine1.Manager"
|
||||||
send_member="MarkImageReadOnly"/>
|
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"
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
send_interface="org.freedesktop.machine1.Machine"
|
send_interface="org.freedesktop.machine1.Machine"
|
||||||
send_member="GetAddresses"/>
|
send_member="GetAddresses"/>
|
||||||
@ -148,6 +156,10 @@
|
|||||||
send_interface="org.freedesktop.machine1.Image"
|
send_interface="org.freedesktop.machine1.Image"
|
||||||
send_member="Clone"/>
|
send_member="Clone"/>
|
||||||
|
|
||||||
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
|
send_interface="org.freedesktop.machine1.Image"
|
||||||
|
send_member="SetLimit"/>
|
||||||
|
|
||||||
<allow send_destination="org.freedesktop.machine1"
|
<allow send_destination="org.freedesktop.machine1"
|
||||||
send_interface="org.freedesktop.machine1.Image"
|
send_interface="org.freedesktop.machine1.Image"
|
||||||
send_member="MarkReadOnly"/>
|
send_member="MarkReadOnly"/>
|
||||||
|
@ -669,3 +669,29 @@ int btrfs_quota_enable(const char *path, bool b) {
|
|||||||
|
|
||||||
return btrfs_quota_enable_fd(fd, 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_fd(int fd, bool b);
|
||||||
int btrfs_quota_enable(const char *path, 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;
|
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) {
|
int image_name_lock(const char *name, int operation, LockFile *ret) {
|
||||||
const char *p;
|
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_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
|
||||||
int image_name_lock(const char *name, int operation, LockFile *ret);
|
int image_name_lock(const char *name, int operation, LockFile *ret);
|
||||||
|
|
||||||
|
int image_set_limit(Image *i, uint64_t referred_max);
|
||||||
|
Reference in New Issue
Block a user