This makes deleting images with many snapshots easier.
Signed-off-by: Josh Durgin <josh.durgin@dreamhost.com>
Resizes rbd image. The size parameter also needs to be specified.
:command:`rm` [*image-name*]
- Deletes rbd image (including all data blocks)
+ Deletes an rbd image (including all data blocks). If the image has
+ snapshots, this fails and nothing is deleted.
:command:`export` [*image-name*] [*dest-path*]
Exports image to dest path.
:command:`snap` rm [*image-name*]
Removes the specified snapshot.
+:command:`snap` purge [*image-name*]
+ Removes all snapshots from an image.
+
:command:`map` [*image-name*]
Maps the specified image to a block device via the rbd kernel module.
Resizes rbd image. The size parameter also needs to be specified.
.TP
.B \fBrm\fP [\fIimage\-name\fP]
-Deletes rbd image (including all data blocks)
+Deletes an rbd image (including all data blocks). If the image has
+snapshots, this fails and nothing is deleted.
.TP
.B \fBexport\fP [\fIimage\-name\fP] [\fIdest\-path\fP]
Exports image to dest path.
.B \fBsnap\fP rm [\fIimage\-name\fP]
Removes the specified snapshot.
.TP
+.B \fBsnap\fP purge [\fIimage\-name\fP]
+Removes all snapshots from an image.
+.TP
.B \fBmap\fP [\fIimage\-name\fP]
Maps the specified image to a block device via the rbd kernel module.
.TP
TMP_FILES="/tmp/img1 /tmp/img1.new /tmp/img2 /tmp/img2.new /tmp/img3 /tmp/img3.new /tmp/img1.snap1"
+rbd snap purge testimg1 || true
rbd rm testimg1 || true
rbd rm testimg2 || true
rbd rm testimg3 || true
rbd unmap /dev/rbd/rbd/testimg1 || true
rbd unmap /dev/rbd/rbd/testimg1@snap1 || true
sudo chown root /sys/bus/rbd/add /sys/bus/rbd/remove
+ rbd snap purge testimg1 || true
rbd rm testimg1 || true
sudo rm -f $TMP_FILES
}
<< " snap create <--snap=name> [image-name] create a snapshot\n"
<< " snap rollback <--snap=name> [image-name] rollback image head to snapshot\n"
<< " snap rm <--snap=name> [image-name] deletes a snapshot\n"
+ << " snap purge [image-name] deletes all snapshots\n"
<< " watch [image-name] watch events on image\n"
<< " map [image-name] map the image to a block device\n"
<< " using the kernel\n"
return 0;
}
+static int do_purge_snaps(librbd::Image& image)
+{
+ MyProgressContext pc("Removing all snapshots");
+ std::vector<librbd::snap_info_t> snaps;
+ int r = image.snap_list(snaps);
+ if (r < 0) {
+ pc.fail();
+ return r;
+ }
+
+ for (size_t i = 0; i < snaps.size(); ++i) {
+ image.snap_remove(snaps[i].name.c_str());
+ pc.update_progress(i + 1, snaps.size());
+ }
+
+ pc.finish();
+ return 0;
+}
+
struct ExportContext {
int fd;
MyProgressContext pc;
OPT_SNAP_ROLLBACK,
OPT_SNAP_REMOVE,
OPT_SNAP_LIST,
+ OPT_SNAP_PURGE,
OPT_WATCH,
OPT_MAP,
OPT_UNMAP,
if (strcmp(cmd, "ls") == 0||
strcmp(cmd, "list") == 0)
return OPT_SNAP_LIST;
+ if (strcmp(cmd, "purge") == 0)
+ return OPT_SNAP_PURGE;
}
return OPT_NO_CMD;
case OPT_SNAP_ROLLBACK:
case OPT_SNAP_REMOVE:
case OPT_SNAP_LIST:
+ case OPT_SNAP_PURGE:
case OPT_WATCH:
case OPT_MAP:
set_conf_param(v, &imgname, NULL);
if (imgname && talk_to_cluster &&
(opt_cmd == OPT_RESIZE || opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST ||
opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK ||
- opt_cmd == OPT_SNAP_REMOVE || opt_cmd == OPT_EXPORT || opt_cmd == OPT_WATCH ||
- opt_cmd == OPT_COPY)) {
+ opt_cmd == OPT_SNAP_REMOVE || opt_cmd == OPT_SNAP_PURGE ||
+ opt_cmd == OPT_EXPORT || opt_cmd == OPT_WATCH || opt_cmd == OPT_COPY)) {
r = rbd.open(io_ctx, image, imgname);
if (r < 0) {
cerr << "error opening image " << imgname << ": " << cpp_strerror(-r) << std::endl;
case OPT_RM:
r = do_delete(rbd, io_ctx, imgname);
if (r < 0) {
- cerr << "delete error: " << cpp_strerror(-r) << std::endl;
+ if (r == -EBUSY) {
+ cerr << "delete error: image has snapshots - these must be deleted"
+ << " with 'rbd snap purge' before the image can be removed."
+ << std::endl;
+ } else {
+ cerr << "delete error: " << cpp_strerror(-r) << std::endl;
+ }
exit(1);
}
break;
}
break;
+ case OPT_SNAP_PURGE:
+ if (!imgname) {
+ usage();
+ exit(1);
+ }
+ r = do_purge_snaps(image);
+ if (r < 0) {
+ cerr << "removing snaps failed: " << cpp_strerror(-r) << std::endl;
+ exit(1);
+ }
+ break;
+
case OPT_EXPORT:
if (!path) {
cerr << "pathname should be specified" << std::endl;
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel
snap create <--snap=name> [image-name] create a snapshot
snap rollback <--snap=name> [image-name] rollback image head to snapshot
snap rm <--snap=name> [image-name] deletes a snapshot
+ snap purge [image-name] deletes all snapshots
watch [image-name] watch events on image
map [image-name] map the image to a block device
using the kernel