Move 'DetermineImageSize' from 'ganeti.cmdlib.backup' to 'ganeti.cmdlib.common' so it can be used by disk zeroing and instance installations. This patch also transforms this method into a function and generalizes the error messages.
Signed-off-by: Jose A. Lopes <[email protected]> --- lib/cmdlib/backup.py | 59 +++++++--------------------------------------------- lib/cmdlib/common.py | 52 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/lib/cmdlib/backup.py b/lib/cmdlib/backup.py index a83d2f0..5f340b3 100644 --- a/lib/cmdlib/backup.py +++ b/lib/cmdlib/backup.py @@ -21,10 +21,8 @@ """Logical units dealing with backup operations.""" -import urllib2 import OpenSSL import logging -import math from ganeti import compat from ganeti import constants @@ -36,7 +34,7 @@ from ganeti.utils import retry from ganeti.cmdlib.base import NoHooksLU, LogicalUnit from ganeti.cmdlib.common import CheckNodeOnline, ExpandNodeUuidAndName, \ - IsInstanceRunning + IsInstanceRunning, DetermineImageSize from ganeti.cmdlib.instance_storage import StartInstanceDisks, \ ShutdownInstanceDisks, TemporaryDisk, ImageDisks from ganeti.cmdlib.instance_utils import GetClusterDomainSecret, \ @@ -347,54 +345,6 @@ class LUBackupExport(LogicalUnit): " on node %s: %s", iname, self.cfg.GetNodeName(node_uuid), msg) - def _DetermineImageSize(self, image_path, node_uuid): - """ Determines the size of the specified image. - - @type image_path: string - @param image_path: The disk path or a URL of an image. - @type node_uuid: string - @param node_uuid: If a file path is used, - - @raise OpExecError: If the image does not exist. - - @rtype: int - @return: The size in MB, rounded up. - - """ - # Check if we are dealing with a URL first - class _HeadRequest(urllib2.Request): - def get_method(self): - return "HEAD" - - if utils.IsUrl(image_path): - try: - response = urllib2.urlopen(_HeadRequest(image_path)) - except urllib2.URLError: - raise errors.OpExecError("Could not retrieve image from given url %s" % - image_path) - - content_length_str = response.info().getheader('content-length') - - if not content_length_str: - raise errors.OpExecError( - "Cannot create temporary disk: size of zeroing image at path %s " - "could not be retrieved through HEAD request" % image_path - ) - - byte_size = int(content_length_str) - else: - # We end up here if a file path is used - result = self.rpc.call_get_file_info(node_uuid, image_path) - result.Raise("Cannot determine the size of file %s" % image_path) - - success, attributes = result.payload - if not success: - raise errors.OpExecError("Could not open file %s" % image_path) - byte_size = attributes[constants.STAT_SIZE] - - # Finally, the conversion - return math.ceil(byte_size / 1024. / 1024.) - def _InstanceDiskSizeSum(self): """Calculates the size of all the disks of the instance used in this LU. @@ -417,7 +367,12 @@ class LUBackupExport(LogicalUnit): zeroing_image = self.cfg.GetZeroingImage() src_node_uuid = self.instance.primary_node - disk_size = self._DetermineImageSize(zeroing_image, src_node_uuid) + + try: + disk_size = DetermineImageSize(self, zeroing_image, src_node_uuid) + except errors.OpExecError, err: + raise errors.OpExecError("Could not create temporary disk for zeroing:" + " %s", err) # Calculate the sum prior to adding the temporary disk instance_disks_size_sum = self._InstanceDiskSizeSum() diff --git a/lib/cmdlib/common.py b/lib/cmdlib/common.py index 9889a67..5e6b670 100644 --- a/lib/cmdlib/common.py +++ b/lib/cmdlib/common.py @@ -22,7 +22,9 @@ """Common functions used by multiple logical units.""" import copy +import math import os +import urllib2 from ganeti import compat from ganeti import constants @@ -764,7 +766,7 @@ def AnnotateDiskParams(instance, devs, cfg): @param devs: The root devices (not any of its children!) @param cfg: The config object @returns The annotated disk copies - @see L{rpc.node.AnnotateDiskParams} + @see L{ganeti.rpc.node.AnnotateDiskParams} """ return rpc.AnnotateDiskParams(devs, cfg.GetInstanceDiskParams(instance)) @@ -1414,3 +1416,51 @@ def ConnectInstanceCommunicationNetworkOp(group_uuid, network): network_mode=constants.INSTANCE_COMMUNICATION_NETWORK_MODE, network_link=constants.INSTANCE_COMMUNICATION_NETWORK_LINK, conflicts_check=True) + + +def DetermineImageSize(lu, image, node_uuid): + """Determines the size of the specified image. + + @type image: string + @param image: absolute filepath or URL of the image + + @type node_uuid: string + @param node_uuid: if L{image} is a filepath, this is the UUID of the + node where the image is located + + @rtype: int + @return: size of the image in MB, rounded up + @raise OpExecError: if the image does not exist + + """ + # Check if we are dealing with a URL first + class _HeadRequest(urllib2.Request): + def get_method(self): + return "HEAD" + + if utils.IsUrl(image): + try: + response = urllib2.urlopen(_HeadRequest(image)) + except urllib2.URLError: + raise errors.OpExecError("Could not retrieve image from given url '%s'" % + image) + + content_length_str = response.info().getheader('content-length') + + if not content_length_str: + raise errors.OpExecError("Could not determine image size from given url" + " '%s'" % image) + + byte_size = int(content_length_str) + else: + # We end up here if a file path is used + result = lu.rpc.call_get_file_info(node_uuid, image) + result.Raise("Could not determine size of file '%s'" % image) + + success, attributes = result.payload + if not success: + raise errors.OpExecError("Could not open file '%s'" % image) + byte_size = attributes[constants.STAT_SIZE] + + # Finally, the conversion + return math.ceil(byte_size / 1024. / 1024.) -- 1.9.1.423.g4596e3a
