lxd/storage_ceph_utils.go
func cephContainerSnapshotDelete(clusterName string, poolName string,
	volumeName string, volumeType string, snapshotName string,
	userName string) int {
	logImageEntry := fmt.Sprintf("%s/%s_%s", poolName, volumeType, volumeName)
	logSnapshotEntry := fmt.Sprintf("%s/%s_%s@%s", poolName, volumeType,
		volumeName, snapshotName)

	clones, err := cephRBDSnapshotListClones(clusterName, poolName,
		volumeName, volumeType, snapshotName, userName)
	if err != nil {
		if err != db.ErrNoSuchObject {
			logger.Errorf(`Failed to list clones of RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`RBD snapshot "%s" of RBD storage volume "%s" does not have any clones`, logSnapshotEntry, logImageEntry)

		// unprotect
		err = cephRBDSnapshotUnprotect(clusterName, poolName, volumeName,
			volumeType, snapshotName, userName)
		if err != nil {
			logger.Errorf(`Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Unprotected RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// unmap
		err = cephRBDVolumeSnapshotUnmap(clusterName, poolName,
			volumeName, volumeType, snapshotName, userName, true)
		if err != nil {
			logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// delete
		err = cephRBDSnapshotDelete(clusterName, poolName, volumeName,
			volumeType, snapshotName, userName)
		if err != nil {
			logger.Errorf(`Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Deleted RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// Only delete the parent image if it is a zombie. If it is not
		// we know that LXD is still using it.
		if strings.HasPrefix(volumeType, "zombie_") {
			ret := cephContainerDelete(clusterName, poolName,
				volumeName, volumeType, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete RBD storage volume "%s"`,
					logImageEntry)
				return -1
			}
			logger.Debugf(`Deleted RBD storage volume "%s"`, logImageEntry)
		}

		return 0
	} else {
		logger.Debugf(`Detected "%v" as clones of RBD snapshot "%s" of RBD storage volume "%s"`, clones, logSnapshotEntry, logImageEntry)

		canDelete := true
		for _, clone := range clones {
			clonePool, cloneType, cloneName, err := parseClone(clone)
			if err != nil {
				logger.Errorf(`Failed to parse clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"`, clone, logSnapshotEntry, logImageEntry)
				return -1
			}
			logger.Debugf(`Split clone "%s" of RBD snapshot "%s" of RBD storage volume "%s" into pool name "%s", volume type "%s", and volume name "%s"`, clone, logSnapshotEntry, logImageEntry, clonePool, cloneType, cloneName)

			if !strings.HasPrefix(cloneType, "zombie_") {
				canDelete = false
				continue
			}

			ret := cephContainerDelete(clusterName, clonePool,
				cloneName, cloneType, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"`, clone, logSnapshotEntry, logImageEntry)
				return -1
			} else if ret == 1 {
				// Only marked as zombie
				canDelete = false
			}
		}

		if canDelete {
			logger.Debugf(`Deleted all clones of RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// unprotect
			err = cephRBDSnapshotUnprotect(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Unprotected RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// unmap
			err = cephRBDVolumeSnapshotUnmap(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName,
				true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// delete
			err = cephRBDSnapshotDelete(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Deleted RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// Only delete the parent image if it is a zombie. If it
			// is not we know that LXD is still using it.
			if strings.HasPrefix(volumeType, "zombie_") {
				ret := cephContainerDelete(clusterName,
					poolName, volumeName, volumeType,
					userName)
				if ret < 0 {
					logger.Errorf(`Failed to delete RBD storage volume "%s"`, logImageEntry)
					return -1
				}
				logger.Debugf(`Deleted RBD storage volume "%s"`,
					logImageEntry)
			}
		} else {
			logger.Debugf(`Could not delete all clones of RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			if strings.HasPrefix(snapshotName, "zombie_") {
				return 1
			}

			err := cephRBDVolumeSnapshotUnmap(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName,
				true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debug(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			newSnapshotName := fmt.Sprintf("zombie_%s", snapshotName)
			logSnapshotNewEntry := fmt.Sprintf("%s/%s_%s@%s",
				poolName, volumeName, volumeType, newSnapshotName)
			err = cephRBDVolumeSnapshotRename(clusterName, poolName,
				volumeName, volumeType, snapshotName,
				newSnapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to rename RBD snapshot "%s" of RBD storage volume "%s" to %s`, logSnapshotEntry, logImageEntry, logSnapshotNewEntry)
				return -1
			}
			logger.Debugf(`Renamed RBD snapshot "%s" of RBD storage volume "%s" to %s`, logSnapshotEntry, logImageEntry, logSnapshotNewEntry)
		}

	}

	return 1
}
func cephContainerSnapshotDelete(clusterName string, poolName string,
	volumeName string, volumeType string, snapshotName string,
	userName string) int {
	logImageEntry := fmt.Sprintf("%s/%s_%s", poolName, volumeType, volumeName)
	logSnapshotEntry := fmt.Sprintf("%s/%s_%s@%s", poolName, volumeType,
		volumeName, snapshotName)

	clones, err := cephRBDSnapshotListClones(clusterName, poolName,
		volumeName, volumeType, snapshotName, userName)
	if err != nil {
		if err != db.ErrNoSuchObject {
			logger.Errorf(`Failed to list clones of RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`RBD snapshot "%s" of RBD storage volume "%s" does not have any clones`, logSnapshotEntry, logImageEntry)

		// unprotect
		err = cephRBDSnapshotUnprotect(clusterName, poolName, volumeName,
			volumeType, snapshotName, userName)
		if err != nil {
			logger.Errorf(`Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Unprotected RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// unmap
		err = cephRBDVolumeSnapshotUnmap(clusterName, poolName,
			volumeName, volumeType, snapshotName, userName, true)
		if err != nil {
			logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// delete
		err = cephRBDSnapshotDelete(clusterName, poolName, volumeName,
			volumeType, snapshotName, userName)
		if err != nil {
			logger.Errorf(`Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
			return -1
		}
		logger.Debugf(`Deleted RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

		// Only delete the parent image if it is a zombie. If it is not
		// we know that LXD is still using it.
		if strings.HasPrefix(volumeType, "zombie_") {
			ret := cephContainerDelete(clusterName, poolName,
				volumeName, volumeType, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete RBD storage volume "%s"`,
					logImageEntry)
				return -1
			}
			logger.Debugf(`Deleted RBD storage volume "%s"`, logImageEntry)
		}

		return 0
	} else {
		logger.Debugf(`Detected "%v" as clones of RBD snapshot "%s" of RBD storage volume "%s"`, clones, logSnapshotEntry, logImageEntry)

		canDelete := true
		for _, clone := range clones {
			clonePool, cloneType, cloneName, err := parseClone(clone)
			if err != nil {
				logger.Errorf(`Failed to parse clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"`, clone, logSnapshotEntry, logImageEntry)
				return -1
			}
			logger.Debugf(`Split clone "%s" of RBD snapshot "%s" of RBD storage volume "%s" into pool name "%s", volume type "%s", and volume name "%s"`, clone, logSnapshotEntry, logImageEntry, clonePool, cloneType, cloneName)

			if !strings.HasPrefix(cloneType, "zombie_") {
				canDelete = false
				continue
			}

			ret := cephContainerDelete(clusterName, clonePool,
				cloneName, cloneType, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"`, clone, logSnapshotEntry, logImageEntry)
				return -1
			} else if ret == 1 {
				// Only marked as zombie
				canDelete = false
			}
		}

		if canDelete {
			logger.Debugf(`Deleted all clones of RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// unprotect
			err = cephRBDSnapshotUnprotect(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Unprotected RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// unmap
			err = cephRBDVolumeSnapshotUnmap(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName,
				true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// delete
			err = cephRBDSnapshotDelete(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debugf(`Deleted RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			// Only delete the parent image if it is a zombie. If it
			// is not we know that LXD is still using it.
			if strings.HasPrefix(volumeType, "zombie_") {
				ret := cephContainerDelete(clusterName,
					poolName, volumeName, volumeType,
					userName)
				if ret < 0 {
					logger.Errorf(`Failed to delete RBD storage volume "%s"`, logImageEntry)
					return -1
				}
				logger.Debugf(`Deleted RBD storage volume "%s"`,
					logImageEntry)
			}
		} else {
			logger.Debugf(`Could not delete all clones of RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			if strings.HasPrefix(snapshotName, "zombie_") {
				return 1
			}

			err := cephRBDVolumeSnapshotUnmap(clusterName, poolName,
				volumeName, volumeType, snapshotName, userName,
				true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s`, logSnapshotEntry, logImageEntry, err)
				return -1
			}
			logger.Debug(`Unmapped RBD snapshot "%s" of RBD storage volume "%s"`, logSnapshotEntry, logImageEntry)

			newSnapshotName := fmt.Sprintf("zombie_%s", snapshotName)
			logSnapshotNewEntry := fmt.Sprintf("%s/%s_%s@%s",
				poolName, volumeName, volumeType, newSnapshotName)
			err = cephRBDVolumeSnapshotRename(clusterName, poolName,
				volumeName, volumeType, snapshotName,
				newSnapshotName, userName)
			if err != nil {
				logger.Errorf(`Failed to rename RBD snapshot "%s" of RBD storage volume "%s" to %s`, logSnapshotEntry, logImageEntry, logSnapshotNewEntry)
				return -1
			}
			logger.Debugf(`Renamed RBD snapshot "%s" of RBD storage volume "%s" to %s`, logSnapshotEntry, logImageEntry, logSnapshotNewEntry)
		}

	}

	return 1
}
func cephContainerSnapshotDelete ( clusterName string , poolName string , volumeName string , volumeType string , snapshotName string , userName string ) int { logImageEntry := fmt . Sprintf ( " " , poolName , volumeType , volumeName ) logSnapshotEntry := fmt . Sprintf ( " " , poolName , volumeType , volumeName , snapshotName ) clones , err := cephRBDSnapshotListClones ( clusterName , poolName , volumeName , volumeType , snapshotName , userName ) if err != nil { if err != db . ErrNoSuchObject { logger . Errorf ( `Failed to list clones of RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `RBD snapshot "%s" of RBD storage volume "%s" does not have any clones` , logSnapshotEntry , logImageEntry ) // unprotect err = cephRBDSnapshotUnprotect ( clusterName , poolName , volumeName , volumeType , snapshotName , userName ) if err != nil { logger . Errorf ( `Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Unprotected RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // unmap err = cephRBDVolumeSnapshotUnmap ( clusterName , poolName , volumeName , volumeType , snapshotName , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Unmapped RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // delete err = cephRBDSnapshotDelete ( clusterName , poolName , volumeName , volumeType , snapshotName , userName ) if err != nil { logger . Errorf ( `Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Deleted RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // Only delete the parent image if it is a zombie. If it is not // we know that LXD is still using it. if strings . HasPrefix ( volumeType , " " ) { ret := cephContainerDelete ( clusterName , poolName , volumeName , volumeType , userName ) if ret < 0 { logger . Errorf ( `Failed to delete RBD storage volume "%s"` , logImageEntry ) return - 1 } logger . Debugf ( `Deleted RBD storage volume "%s"` , logImageEntry ) } return 0 } else { logger . Debugf ( `Detected "%v" as clones of RBD snapshot "%s" of RBD storage volume "%s"` , clones , logSnapshotEntry , logImageEntry ) canDelete := true for _ , clone := range clones { clonePool , cloneType , cloneName , err := parseClone ( clone ) if err != nil { logger . Errorf ( `Failed to parse clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"` , clone , logSnapshotEntry , logImageEntry ) return - 1 } logger . Debugf ( `Split clone "%s" of RBD snapshot "%s" of RBD storage volume "%s" into pool name "%s", volume type "%s", and volume name "%s"` , clone , logSnapshotEntry , logImageEntry , clonePool , cloneType , cloneName ) if ! strings . HasPrefix ( cloneType , " " ) { canDelete = false continue } ret := cephContainerDelete ( clusterName , clonePool , cloneName , cloneType , userName ) if ret < 0 { logger . Errorf ( `Failed to delete clone "%s" of RBD snapshot "%s" of RBD storage volume "%s"` , clone , logSnapshotEntry , logImageEntry ) return - 1 } else if ret == 1 { // Only marked as zombie canDelete = false } } if canDelete { logger . Debugf ( `Deleted all clones of RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // unprotect err = cephRBDSnapshotUnprotect ( clusterName , poolName , volumeName , volumeType , snapshotName , userName ) if err != nil { logger . Errorf ( `Failed to unprotect RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Unprotected RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // unmap err = cephRBDVolumeSnapshotUnmap ( clusterName , poolName , volumeName , volumeType , snapshotName , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Unmapped RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // delete err = cephRBDSnapshotDelete ( clusterName , poolName , volumeName , volumeType , snapshotName , userName ) if err != nil { logger . Errorf ( `Failed to delete RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debugf ( `Deleted RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) // Only delete the parent image if it is a zombie. If it // is not we know that LXD is still using it. if strings . HasPrefix ( volumeType , " " ) { ret := cephContainerDelete ( clusterName , poolName , volumeName , volumeType , userName ) if ret < 0 { logger . Errorf ( `Failed to delete RBD storage volume "%s"` , logImageEntry ) return - 1 } logger . Debugf ( `Deleted RBD storage volume "%s"` , logImageEntry ) } } else { logger . Debugf ( `Could not delete all clones of RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) if strings . HasPrefix ( snapshotName , " " ) { return 1 } err := cephRBDVolumeSnapshotUnmap ( clusterName , poolName , volumeName , volumeType , snapshotName , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD snapshot "%s" of RBD storage volume "%s": %s` , logSnapshotEntry , logImageEntry , err ) return - 1 } logger . Debug ( `Unmapped RBD snapshot "%s" of RBD storage volume "%s"` , logSnapshotEntry , logImageEntry ) newSnapshotName := fmt . Sprintf ( " " , snapshotName ) logSnapshotNewEntry := fmt . Sprintf ( " " , poolName , volumeName , volumeType , newSnapshotName ) err = cephRBDVolumeSnapshotRename ( clusterName , poolName , volumeName , volumeType , snapshotName , newSnapshotName , userName ) if err != nil { logger . Errorf ( `Failed to rename RBD snapshot "%s" of RBD storage volume "%s" to %s` , logSnapshotEntry , logImageEntry , logSnapshotNewEntry ) return - 1 } logger . Debugf ( `Renamed RBD snapshot "%s" of RBD storage volume "%s" to %s` , logSnapshotEntry , logImageEntry , logSnapshotNewEntry ) } } return 1 }
// cephContainerSnapshotDelete deletes an RBD snapshot of a container including
// any dependencies
// - This function takes care to delete any RBD storage entities that are marked
//   as zombie and whose existence is solely dependent on the RBD snapshot for
//   the container to be deleted.
// - This function will mark any storage entities of the container to be deleted
//   as zombies in case any RBD storage entities in the storage pool have a
//   dependency relation with it.
// - This function uses a C-style convention to return error or success simply
//   because it is more elegant and simple than the go way.
//   The function will return
//   -1 on error
//    0 if the RBD storage volume has been deleted
//    1 if the RBD storage volume has been marked as a zombie
// - cephContainerSnapshotDelete in conjunction with cephContainerDelete
//   recurses through an OSD storage pool to find and delete any storage
//   entities that were kept around because of dependency relations but are not
//   deletable.
cephContainerSnapshotDelete deletes an RBD snapshot of a container including any dependencies - This function takes care to delete any RBD storage entities that are marked as zombie and whose existence is solely dependent on the RBD snapshot for the container to be deleted . - This function will mark any storage entities of the container to be deleted as zombies in case any RBD storage entities in the storage pool have a dependency relation with it . - This function uses a C - style convention to return error or success simply because it is more elegant and simple than the go way . The function will return - 1 on error 0 if the RBD storage volume has been deleted 1 if the RBD storage volume has been marked as a zombie - cephContainerSnapshotDelete in conjunction with cephContainerDelete recurses through an OSD storage pool to find and delete any storage entities that were kept around because of dependency relations but are not deletable .