|
55 | 55 |
|
56 | 56 | import com.ceph.rados.IoCTX; |
57 | 57 | import com.ceph.rados.Rados; |
58 | | -import com.ceph.rados.exceptions.ErrorCode; |
59 | 58 | import com.ceph.rados.exceptions.RadosException; |
60 | 59 | import com.ceph.rbd.Rbd; |
61 | 60 | import com.ceph.rbd.RbdException; |
@@ -95,6 +94,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { |
95 | 94 | private static final int RBD_FEATURE_DEEP_FLATTEN = 32; |
96 | 95 | public static final int RBD_FEATURES = RBD_FEATURE_LAYERING + RBD_FEATURE_EXCLUSIVE_LOCK + RBD_FEATURE_OBJECT_MAP + RBD_FEATURE_FAST_DIFF + RBD_FEATURE_DEEP_FLATTEN; |
97 | 96 | private int rbdOrder = 0; /* Order 0 means 4MB blocks (the default) */ |
| 97 | + /* libvirt's VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS, not exposed as a constant by libvirt-java */ |
| 98 | + private static final int VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS = 2; |
98 | 99 |
|
99 | 100 | private static final Set<StoragePoolType> QEMU_IMG_MANAGED_POOL_TYPES = Set.of(StoragePoolType.NetworkFilesystem, StoragePoolType.Filesystem, StoragePoolType.SharedMountPoint); |
100 | 101 |
|
@@ -1150,61 +1151,6 @@ public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool, Storage.Imag |
1150 | 1151 |
|
1151 | 1152 | logger.info("Attempting to remove volume " + uuid + " from pool " + pool.getUuid()); |
1152 | 1153 |
|
1153 | | - /** |
1154 | | - * RBD volume can have snapshots and while they exist libvirt |
1155 | | - * can't remove the RBD volume |
1156 | | - * |
1157 | | - * We have to remove those snapshots first |
1158 | | - */ |
1159 | | - if (pool.getType() == StoragePoolType.RBD) { |
1160 | | - try { |
1161 | | - logger.info("Unprotecting and Removing RBD snapshots of image " + pool.getSourceDir() + "/" + uuid + " prior to removing the image"); |
1162 | | - |
1163 | | - Rados r = new Rados(pool.getAuthUserName()); |
1164 | | - r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort()); |
1165 | | - r.confSet("key", pool.getAuthSecret()); |
1166 | | - r.confSet("client_mount_timeout", "30"); |
1167 | | - r.connect(); |
1168 | | - logger.debug("Successfully connected to Ceph cluster at " + r.confGet("mon_host")); |
1169 | | - |
1170 | | - IoCTX io = r.ioCtxCreate(pool.getSourceDir()); |
1171 | | - Rbd rbd = new Rbd(io); |
1172 | | - RbdImage image = rbd.open(uuid); |
1173 | | - logger.debug("Fetching list of snapshots of RBD image " + pool.getSourceDir() + "/" + uuid); |
1174 | | - List<RbdSnapInfo> snaps = image.snapList(); |
1175 | | - try { |
1176 | | - for (RbdSnapInfo snap : snaps) { |
1177 | | - if (image.snapIsProtected(snap.name)) { |
1178 | | - logger.debug("Unprotecting snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name); |
1179 | | - image.snapUnprotect(snap.name); |
1180 | | - } else { |
1181 | | - logger.debug("Snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name + " is not protected."); |
1182 | | - } |
1183 | | - logger.debug("Removing snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name); |
1184 | | - image.snapRemove(snap.name); |
1185 | | - } |
1186 | | - logger.info("Successfully unprotected and removed any remaining snapshots (" + snaps.size() + ") of " |
1187 | | - + pool.getSourceDir() + "/" + uuid + " Continuing to remove the RBD image"); |
1188 | | - } catch (RbdException e) { |
1189 | | - logger.error("Failed to remove snapshot with exception: " + e.toString() + |
1190 | | - ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1191 | | - throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1192 | | - } finally { |
1193 | | - logger.debug("Closing image and destroying context"); |
1194 | | - rbd.close(image); |
1195 | | - r.ioCtxDestroy(io); |
1196 | | - } |
1197 | | - } catch (RadosException e) { |
1198 | | - logger.error("Failed to remove snapshot with exception: " + e.toString() + |
1199 | | - ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1200 | | - throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1201 | | - } catch (RbdException e) { |
1202 | | - logger.error("Failed to remove snapshot with exception: " + e.toString() + |
1203 | | - ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1204 | | - throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue())); |
1205 | | - } |
1206 | | - } |
1207 | | - |
1208 | 1154 | LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool; |
1209 | 1155 | try { |
1210 | 1156 | StorageVol vol = getVolume(libvirtPool.getPool(), uuid); |
@@ -1721,7 +1667,19 @@ private void refreshPool(StoragePool pool) throws LibvirtException { |
1721 | 1667 | } |
1722 | 1668 |
|
1723 | 1669 | private void deleteVol(LibvirtStoragePool pool, StorageVol vol) throws LibvirtException { |
1724 | | - vol.delete(0); |
| 1670 | + /** |
| 1671 | + * RBD volumes can have snapshots, and libvirt refuses to remove a volume while |
| 1672 | + * they exist. VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS tells the RBD storage backend |
| 1673 | + * to unprotect and remove any snapshots before removing the volume itself. |
| 1674 | + * |
| 1675 | + * libvirt-java has no named constant for this flag (added upstream in libvirt 1.2.20, |
| 1676 | + * commit 3c7590e0a4), so it's passed as a raw flag value here. |
| 1677 | + */ |
| 1678 | + int flags = 0; |
| 1679 | + if (pool.getType() == StoragePoolType.RBD) { |
| 1680 | + flags |= VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS; |
| 1681 | + } |
| 1682 | + vol.delete(flags); |
1725 | 1683 | } |
1726 | 1684 |
|
1727 | 1685 |
|
|
0 commit comments