lxd/storage_ceph_utils.go
func cephContainerDelete(clusterName string, poolName string, volumeName string,
	volumeType string, userName string) int {
	logEntry := fmt.Sprintf("%s/%s_%s", poolName, volumeType, volumeName)

	snaps, err := cephRBDVolumeListSnapshots(clusterName, poolName,
		volumeName, volumeType, userName)
	if err == nil {
		var zombies int
		for _, snap := range snaps {
			logEntry := fmt.Sprintf("%s/%s_%s@%s", poolName,
				volumeType, volumeName, snap)

			ret := cephContainerSnapshotDelete(clusterName,
				poolName, volumeName, volumeType, snap, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete RBD storage volume "%s"`, logEntry)
				return -1
			} else if ret == 1 {
				logger.Debugf(`Marked RBD storage volume "%s" as zombie`, logEntry)
				zombies++
			} else {
				logger.Debugf(`Deleted RBD storage volume "%s"`, logEntry)
			}
		}

		if zombies > 0 {
			// unmap
			err = cephRBDVolumeUnmap(clusterName, poolName,
				volumeName, volumeType, userName, true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD storage volume "%s": %s`, logEntry, err)
				return -1
			}
			logger.Debugf(`Unmapped RBD storage volume "%s"`, logEntry)

			if strings.HasPrefix(volumeType, "zombie_") {
				logger.Debugf(`RBD storage volume "%s" already marked as zombie`, logEntry)
				return 1
			}

			newVolumeName := fmt.Sprintf("%s_%s", volumeName,
				uuid.NewRandom().String())
			err := cephRBDVolumeMarkDeleted(clusterName, poolName,
				volumeType, volumeName, newVolumeName, userName,
				"")
			if err != nil {
				logger.Errorf(`Failed to mark RBD storage volume "%s" as zombie: %s`, logEntry, err)
				return -1
			}
			logger.Debugf(`Marked RBD storage volume "%s" as zombie`, logEntry)

			return 1
		}
	} else {
		if err != db.ErrNoSuchObject {
			logger.Errorf(`Failed to retrieve snapshots of RBD storage volume: %s`, err)
			return -1
		}

		parent, err := cephRBDVolumeGetParent(clusterName, poolName,
			volumeName, volumeType, userName)
		if err == nil {
			logger.Debugf(`Detected "%s" as parent of RBD storage volume "%s"`, parent, logEntry)
			_, parentVolumeType, parentVolumeName,
				parentSnapshotName, err := parseParent(parent)
			if err != nil {
				logger.Errorf(`Failed to parse parent "%s" of RBD storage volume "%s"`, parent, logEntry)
				return -1
			}
			logger.Debugf(`Split parent "%s" of RBD storage volume "%s" into volume type "%s", volume name "%s", and snapshot name "%s"`, parent, logEntry, parentVolumeType,
				parentVolumeName, parentSnapshotName)

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

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

			// Only delete the parent snapshot of the container if
			// it is a zombie. If it is not we know that LXD is
			// still using it.
			if strings.HasPrefix(parentVolumeType, "zombie_") ||
				strings.HasPrefix(parentSnapshotName, "zombie_") {
				ret := cephContainerSnapshotDelete(clusterName,
					poolName, parentVolumeName,
					parentVolumeType, parentSnapshotName,
					userName)
				if ret < 0 {
					logger.Errorf(`Failed to delete snapshot "%s" of RBD storage volume "%s"`, parentSnapshotName, logEntry)
					return -1
				}
				logger.Debugf(`Deleteed snapshot "%s" of RBD storage volume "%s"`, parentSnapshotName, logEntry)
			}

			return 0
		} else {
			if err != db.ErrNoSuchObject {
				logger.Errorf(`Failed to retrieve parent of RBD storage volume "%s"`, logEntry)
				return -1
			}
			logger.Debugf(`RBD storage volume "%s" does not have parent`, logEntry)

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

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

		}
	}

	return 0
}
func cephContainerDelete(clusterName string, poolName string, volumeName string,
	volumeType string, userName string) int {
	logEntry := fmt.Sprintf("%s/%s_%s", poolName, volumeType, volumeName)

	snaps, err := cephRBDVolumeListSnapshots(clusterName, poolName,
		volumeName, volumeType, userName)
	if err == nil {
		var zombies int
		for _, snap := range snaps {
			logEntry := fmt.Sprintf("%s/%s_%s@%s", poolName,
				volumeType, volumeName, snap)

			ret := cephContainerSnapshotDelete(clusterName,
				poolName, volumeName, volumeType, snap, userName)
			if ret < 0 {
				logger.Errorf(`Failed to delete RBD storage volume "%s"`, logEntry)
				return -1
			} else if ret == 1 {
				logger.Debugf(`Marked RBD storage volume "%s" as zombie`, logEntry)
				zombies++
			} else {
				logger.Debugf(`Deleted RBD storage volume "%s"`, logEntry)
			}
		}

		if zombies > 0 {
			// unmap
			err = cephRBDVolumeUnmap(clusterName, poolName,
				volumeName, volumeType, userName, true)
			if err != nil {
				logger.Errorf(`Failed to unmap RBD storage volume "%s": %s`, logEntry, err)
				return -1
			}
			logger.Debugf(`Unmapped RBD storage volume "%s"`, logEntry)

			if strings.HasPrefix(volumeType, "zombie_") {
				logger.Debugf(`RBD storage volume "%s" already marked as zombie`, logEntry)
				return 1
			}

			newVolumeName := fmt.Sprintf("%s_%s", volumeName,
				uuid.NewRandom().String())
			err := cephRBDVolumeMarkDeleted(clusterName, poolName,
				volumeType, volumeName, newVolumeName, userName,
				"")
			if err != nil {
				logger.Errorf(`Failed to mark RBD storage volume "%s" as zombie: %s`, logEntry, err)
				return -1
			}
			logger.Debugf(`Marked RBD storage volume "%s" as zombie`, logEntry)

			return 1
		}
	} else {
		if err != db.ErrNoSuchObject {
			logger.Errorf(`Failed to retrieve snapshots of RBD storage volume: %s`, err)
			return -1
		}

		parent, err := cephRBDVolumeGetParent(clusterName, poolName,
			volumeName, volumeType, userName)
		if err == nil {
			logger.Debugf(`Detected "%s" as parent of RBD storage volume "%s"`, parent, logEntry)
			_, parentVolumeType, parentVolumeName,
				parentSnapshotName, err := parseParent(parent)
			if err != nil {
				logger.Errorf(`Failed to parse parent "%s" of RBD storage volume "%s"`, parent, logEntry)
				return -1
			}
			logger.Debugf(`Split parent "%s" of RBD storage volume "%s" into volume type "%s", volume name "%s", and snapshot name "%s"`, parent, logEntry, parentVolumeType,
				parentVolumeName, parentSnapshotName)

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

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

			// Only delete the parent snapshot of the container if
			// it is a zombie. If it is not we know that LXD is
			// still using it.
			if strings.HasPrefix(parentVolumeType, "zombie_") ||
				strings.HasPrefix(parentSnapshotName, "zombie_") {
				ret := cephContainerSnapshotDelete(clusterName,
					poolName, parentVolumeName,
					parentVolumeType, parentSnapshotName,
					userName)
				if ret < 0 {
					logger.Errorf(`Failed to delete snapshot "%s" of RBD storage volume "%s"`, parentSnapshotName, logEntry)
					return -1
				}
				logger.Debugf(`Deleteed snapshot "%s" of RBD storage volume "%s"`, parentSnapshotName, logEntry)
			}

			return 0
		} else {
			if err != db.ErrNoSuchObject {
				logger.Errorf(`Failed to retrieve parent of RBD storage volume "%s"`, logEntry)
				return -1
			}
			logger.Debugf(`RBD storage volume "%s" does not have parent`, logEntry)

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

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

		}
	}

	return 0
}
func cephContainerDelete ( clusterName string , poolName string , volumeName string , volumeType string , userName string ) int { logEntry := fmt . Sprintf ( " " , poolName , volumeType , volumeName ) snaps , err := cephRBDVolumeListSnapshots ( clusterName , poolName , volumeName , volumeType , userName ) if err == nil { var zombies int for _ , snap := range snaps { logEntry := fmt . Sprintf ( " " , poolName , volumeType , volumeName , snap ) ret := cephContainerSnapshotDelete ( clusterName , poolName , volumeName , volumeType , snap , userName ) if ret < 0 { logger . Errorf ( `Failed to delete RBD storage volume "%s"` , logEntry ) return - 1 } else if ret == 1 { logger . Debugf ( `Marked RBD storage volume "%s" as zombie` , logEntry ) zombies ++ } else { logger . Debugf ( `Deleted RBD storage volume "%s"` , logEntry ) } } if zombies > 0 { // unmap err = cephRBDVolumeUnmap ( clusterName , poolName , volumeName , volumeType , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD storage volume "%s": %s` , logEntry , err ) return - 1 } logger . Debugf ( `Unmapped RBD storage volume "%s"` , logEntry ) if strings . HasPrefix ( volumeType , " " ) { logger . Debugf ( `RBD storage volume "%s" already marked as zombie` , logEntry ) return 1 } newVolumeName := fmt . Sprintf ( " " , volumeName , uuid . NewRandom ( ) . String ( ) ) err := cephRBDVolumeMarkDeleted ( clusterName , poolName , volumeType , volumeName , newVolumeName , userName , " " ) if err != nil { logger . Errorf ( `Failed to mark RBD storage volume "%s" as zombie: %s` , logEntry , err ) return - 1 } logger . Debugf ( `Marked RBD storage volume "%s" as zombie` , logEntry ) return 1 } } else { if err != db . ErrNoSuchObject { logger . Errorf ( `Failed to retrieve snapshots of RBD storage volume: %s` , err ) return - 1 } parent , err := cephRBDVolumeGetParent ( clusterName , poolName , volumeName , volumeType , userName ) if err == nil { logger . Debugf ( `Detected "%s" as parent of RBD storage volume "%s"` , parent , logEntry ) _ , parentVolumeType , parentVolumeName , parentSnapshotName , err := parseParent ( parent ) if err != nil { logger . Errorf ( `Failed to parse parent "%s" of RBD storage volume "%s"` , parent , logEntry ) return - 1 } logger . Debugf ( `Split parent "%s" of RBD storage volume "%s" into volume type "%s", volume name "%s", and snapshot name "%s"` , parent , logEntry , parentVolumeType , parentVolumeName , parentSnapshotName ) // unmap err = cephRBDVolumeUnmap ( clusterName , poolName , volumeName , volumeType , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD storage volume "%s": %s` , logEntry , err ) return - 1 } logger . Debugf ( `Unmapped RBD storage volume "%s"` , logEntry ) // delete err = cephRBDVolumeDelete ( clusterName , poolName , volumeName , volumeType , userName ) if err != nil { logger . Errorf ( `Failed to delete RBD storage volume "%s": %s` , logEntry , err ) return - 1 } logger . Debugf ( `Deleted RBD storage volume "%s"` , logEntry ) // Only delete the parent snapshot of the container if // it is a zombie. If it is not we know that LXD is // still using it. if strings . HasPrefix ( parentVolumeType , " " ) || strings . HasPrefix ( parentSnapshotName , " " ) { ret := cephContainerSnapshotDelete ( clusterName , poolName , parentVolumeName , parentVolumeType , parentSnapshotName , userName ) if ret < 0 { logger . Errorf ( `Failed to delete snapshot "%s" of RBD storage volume "%s"` , parentSnapshotName , logEntry ) return - 1 } logger . Debugf ( `Deleteed snapshot "%s" of RBD storage volume "%s"` , parentSnapshotName , logEntry ) } return 0 } else { if err != db . ErrNoSuchObject { logger . Errorf ( `Failed to retrieve parent of RBD storage volume "%s"` , logEntry ) return - 1 } logger . Debugf ( `RBD storage volume "%s" does not have parent` , logEntry ) // unmap err = cephRBDVolumeUnmap ( clusterName , poolName , volumeName , volumeType , userName , true ) if err != nil { logger . Errorf ( `Failed to unmap RBD storage volume "%s": %s` , logEntry , err ) return - 1 } logger . Debugf ( `Unmapped RBD storage volume "%s"` , logEntry ) // delete err = cephRBDVolumeDelete ( clusterName , poolName , volumeName , volumeType , userName ) if err != nil { logger . Errorf ( `Failed to delete RBD storage volume "%s": %s` , logEntry , err ) return - 1 } logger . Debugf ( `Deleted RBD storage volume "%s"` , logEntry ) } } return 0 }
// cephContainerDelete deletes the RBD storage volume 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 storage volume
//   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
// - cephContainerDelete in conjunction with cephContainerSnapshotDelete
//   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.
cephContainerDelete deletes the RBD storage volume 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 storage volume 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 - cephContainerDelete in conjunction with cephContainerSnapshotDelete 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 .