+ def _CreateSnapshots(self, feedback_fn):
+ """Creates an LVM snapshot for every disk of the instance.
+
+ @return: List of snapshots as L{objects.Disk} instances
+
+ """
+ instance = self.instance
+ src_node = instance.primary_node
+
+ vgname = self.cfg.GetVGName()
+
+ snap_disks = []
+
+ for idx, disk in enumerate(instance.disks):
+ feedback_fn("Creating a snapshot of disk/%s on node %s" %
+ (idx, src_node))
+
+ # result.payload will be a snapshot of an lvm leaf of the one we
+ # passed
+ result = self.rpc.call_blockdev_snapshot(src_node, disk)
+ msg = result.fail_msg
+ if msg:
+ self.LogWarning("Could not snapshot disk/%s on node %s: %s",
+ idx, src_node, msg)
+ snap_disks.append(False)
+ else:
+ disk_id = (vgname, result.payload)
+ new_dev = objects.Disk(dev_type=constants.LD_LV, size=disk.size,
+ logical_id=disk_id, physical_id=disk_id,
+ iv_name=disk.iv_name)
+ snap_disks.append(new_dev)
+
+ return snap_disks
+
+ def _RemoveSnapshot(self, feedback_fn, snap_disks, disk_index):
+ """Removes an LVM snapshot.
+
+ @type snap_disks: list
+ @param snap_disks: The list of all snapshots as returned by
+ L{_CreateSnapshots}
+ @type disk_index: number
+ @param disk_index: Index of the snapshot to be removed
+ @rtype: bool
+ @return: Whether removal was successful or not
+
+ """
+ disk = snap_disks[disk_index]
+ if disk:
+ src_node = self.instance.primary_node
+
+ feedback_fn("Removing snapshot of disk/%s on node %s" %
+ (disk_index, src_node))
+
+ result = self.rpc.call_blockdev_remove(src_node, disk)
+ if not result.fail_msg:
+ return True
+
+ self.LogWarning("Could not remove snapshot for disk/%d from node"
+ " %s: %s", disk_index, src_node, result.fail_msg)
+
+ return False
+
+ def _CleanupExports(self, feedback_fn):
+ """Removes exports of current instance from all other nodes.
+
+ If an instance in a cluster with nodes A..D was exported to node C, its
+ exports will be removed from the nodes A, B and D.
+
+ """
+ nodelist = self.cfg.GetNodeList()
+ nodelist.remove(self.dst_node.name)
+
+ # on one-node clusters nodelist will be empty after the removal
+ # if we proceed the backup would be removed because OpQueryExports
+ # substitutes an empty list with the full cluster node list.
+ iname = self.instance.name
+ if nodelist:
+ feedback_fn("Removing old exports for instance %s" % iname)
+ exportlist = self.rpc.call_export_list(nodelist)
+ for node in exportlist:
+ if exportlist[node].fail_msg:
+ continue
+ if iname in exportlist[node].payload:
+ msg = self.rpc.call_export_remove(node, iname).fail_msg
+ if msg:
+ self.LogWarning("Could not remove older export for instance %s"
+ " on node %s: %s", iname, node, msg)
+