]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machined,machinectl: add calls for changing container/VM quotas
authorLennart Poettering <lennart@poettering.net>
Tue, 24 Feb 2015 22:50:37 +0000 (23:50 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 25 Feb 2015 21:06:54 +0000 (22:06 +0100)
man/machinectl.xml
src/machine/image-dbus.c
src/machine/image-dbus.h
src/machine/machinectl.c
src/machine/machined-dbus.c
src/machine/org.freedesktop.machine1.conf
src/shared/btrfs-util.c
src/shared/btrfs-util.h
src/shared/machine-image.c
src/shared/machine-image.h

index 640cb8b7d691ef6093030460ab86e6bdbd68d627..b50f03f36fdd998a960b120b4bb1c2215ccb3e28 100644 (file)
       <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.
       <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>
       <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>
index 9061017eefce7a8396d92aebe6f71a0827ad93be..12c879aff01f10ed79eb8df584caaeb4cfa4674f 100644 (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
 };
 
index 1b4364cbea3f180e1e4290596b138bf3db9112ea..b9def6bc1b7853f1a15ad105ff7d2f87308f1509 100644 (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);
index ddd2a4aadb43bbf81cd0b506f49a5eb21110ad09..d25b5266b8eeabc22580d79f3092cb8d4a0310b6 100644 (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         },
                 {}
         };
 
index c4f60b5b02dd18a2557adf4abd56668e3e092f18..fdb9d5fac872df0eb3c43bbd8c1c8f243b1ddcd7 100644 (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
index 0e9993348833b0e8efd0176fd4ae714313294852..93aaf6a377e97dd29aa45e21f3531fc46e1eb52f 100644 (file)
                        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"/>
                        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"/>
index 980963b74880149a507582b2a30afa46eba0ce80..6761501da2589166a108be55d0ff9ae39386b4d0 100644 (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);
+}
index 93c3f13ed54f78056a68fff6743de5e89b0ff72c..9a1eb3f38328ec4ce2c7bcdc7bb8ea8f0888daba 100644 (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);
index c734f148aec6d5f96d0742a8242052f680946955..c6d2850ad2dcf9d901f3dce0f5ffe4d6b1a1e4f3 100644 (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;
 
index 314fd6da5811e6de3b024c8f9a69c84a0d45b833..df2394991f1b9bfc79ef0fb8c9fc9b718fd3a498 100644 (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);