⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xendqcowstoragerepo.py

📁 xen 3.2.2 源码
💻 PY
字号:
#!/usr/bin/python#============================================================================# This library is free software; you can redistribute it and/or# modify it under the terms of version 2.1 of the GNU Lesser General Public# License as published by the Free Software Foundation.## This library is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU# Lesser General Public License for more details.## You should have received a copy of the GNU Lesser General Public# License along with this library; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA#============================================================================# Copyright (C) 2006,2007 XenSource Ltd.#============================================================================## The default QCOW Xen API Storage Repository#import commandsimport loggingimport osimport statimport threadingimport reimport sysimport structfrom xen.util import mkdirimport uuidfrom XendPBD import XendPBDfrom XendError import XendErrorfrom XendVDI import *from XendTask import XendTaskfrom XendStorageRepository import XendStorageRepositoryfrom XendOptions import instance as xendoptionsXEND_STORAGE_NO_MAXIMUM = sys.maxintXEND_STORAGE_QCOW_FILENAME = "%s.qcow"XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"MB = 1024 * 1024log = logging.getLogger("xend.XendQCowStorageRepo")def qcow_virtual_size(qcow_file):    """Read the first 32 bytes of the QCoW header to determine its size.    See: http://www.gnome.org/~markmc/qcow-image-format.html.    """    try:        qcow_header = open(qcow_file, 'rb').read(32)        parts = struct.unpack('>IIQIIQ', qcow_header)        return parts[-1]    except IOError:        return -1class XendQCoWStorageRepo(XendStorageRepository):    """A simple file backed QCOW Storage Repository.    This class exposes the interface to create VDI's via the    Xen API. The backend is a file-backed QCOW format that is stored    in XEND_STORAGE_DIR or any that is specified in the constructor.    The actual images are created in the format <uuid>.img and <uuid>.qcow.    """        def __init__(self, sr_uuid,                 sr_type = "qcow_file",                 name_label = "QCoW",                 name_description = "Xend QCoW Storage Repository",                 storage_max = XEND_STORAGE_NO_MAXIMUM):        """        @keyword storage_max: Maximum disk space to use in bytes.        @type    storage_max: int        @ivar    storage_free: storage space free for this repository        @ivar    images: mapping of all the images.        @type    images: dictionary by image uuid.        @ivar    lock:   lock to provide thread safety.        """        XendStorageRepository.__init__(self, sr_uuid, sr_type, name_label,                                       name_description, storage_max)        self.storage_free = 0        self.location = xendoptions().get_xend_storage_path()        self._refresh()    def get_record(self, transient = True):        retval = {'uuid': self.uuid,                  'name_label': self.name_label,                  'name_description': self.name_description,                  'virtual_allocation': self.virtual_allocation,                  'physical_utilisation': self.physical_utilisation,                  'physical_size': self.physical_size,                  'type': self.type,                  'content_type': self.content_type,                  'VDIs': self.images.keys(),                  'PBDs': XendPBD.get_by_SR(self.uuid)}                if self.physical_size == XEND_STORAGE_NO_MAXIMUM:            stfs = os.statvfs(self.location)            retval['physical_size'] = stfs.f_blocks * stfs.f_frsize        return retval            def _refresh(self):        """Internal function that refreshes the state of the disk and        updates the list of images available.        """        self.lock.acquire()        try:            mkdir.parents(self.location, stat.S_IRWXU)            # scan the directory and populate self.images            virtual_alloc = 0            physical_used = 0            seen_images = []            for filename in os.listdir(self.location):                if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:                    image_uuid = filename[:-5]                    seen_images.append(image_uuid)                    qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid                    cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid                    qcow_path = os.path.join(self.location, qcow_file)                    cfg_path = os.path.join(self.location, cfg_file)                                        phys_size = os.stat(qcow_path).st_size                    virt_size = qcow_virtual_size(qcow_path)                                        # add this image if we haven't seen it before                    if image_uuid not in self.images:                        vdi = XendQCoWVDI(image_uuid, self.uuid,                                          qcow_path, cfg_path,                                          virt_size, phys_size)                                                if cfg_path and os.path.exists(cfg_path):                            try:                                vdi.load_config(cfg_path)                            except:                                log.error('Corrupt VDI configuration file %s' %                                          cfg_path)                                                self.images[image_uuid] = vdi                    physical_used += phys_size                    virtual_alloc += virt_size            # remove images that aren't valid            for image_uuid in self.images.keys():                if image_uuid not in seen_images:                    try:                        os.unlink(self.images[image_uuid].qcow_path)                    except OSError:                        pass                    del self.images[image_uuid]            self.virtual_allocation = virtual_alloc            self.physical_utilisation = physical_used            # update free storage if we have to track that            if self.physical_size == XEND_STORAGE_NO_MAXIMUM:                self.storage_free = self._get_free_space()            else:                self.storage_free = self.physical_size - self.virtual_allocation                                finally:            self.lock.release()    def _get_free_space(self):        """Returns the amount of free space in bytes available in the storage        partition. Note that this may not be used if the storage repository        is initialised with a maximum size in storage_max.        @rtype: int        """        stfs = os.statvfs(self.location)        return stfs.f_bavail * stfs.f_frsize    def _has_space_available_for(self, size_bytes):        """Returns whether there is enough space for an image in the        partition which the storage_dir resides on.        @rtype: bool        """        if self.physical_size != XEND_STORAGE_NO_MAXIMUM:            return self.storage_free > size_bytes                bytes_free = self._get_free_space()        if size_bytes < bytes_free:            return True        return False    def _create_image_files(self, desired_size_bytes):        """Create an image and return its assigned UUID.        @param desired_size_bytes: Desired image size in bytes        @type  desired_size_bytes: int        @rtype: string        @return: uuid        @raises XendError: If an error occurs.        """        self.lock.acquire()        try:            if not self._has_space_available_for(desired_size_bytes):                raise XendError("Not enough space (need %d)" %                                desired_size_bytes)            image_uuid = uuid.createString()            qcow_path = os.path.join(self.location,                                     XEND_STORAGE_QCOW_FILENAME % image_uuid)                        if qcow_path and os.path.exists(qcow_path):                raise XendError("Image with same UUID alreaady exists:" %                                image_uuid)                        cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)            rc, output = commands.getstatusoutput(cmd)                        if rc != 0:                # cleanup the image file                os.unlink(qcow_path)                raise XendError("Failed to create QCOW Image: %s" % output)            self._refresh()            return image_uuid        finally:            self.lock.release()    def destroy_vdi(self, image_uuid):        """Destroy an image that is managed by this storage repository.        @param image_uuid: Image UUID        @type  image_uuid: String        @rtype: String        """        self.lock.acquire()        try:            if image_uuid in self.images:                # TODO: check if it is being used?                qcow_path = self.images[image_uuid].qcow_path                cfg_path = self.images[image_uuid].cfg_path                try:                    os.unlink(qcow_path)                    if cfg_path and os.path.exists(cfg_path):                        os.unlink(cfg_path)                except OSError:                    log.exception("Failed to destroy image")                del self.images[image_uuid]                self._refresh()                return True        finally:            self.lock.release()                return False    def list_images(self):        """ List all the available images by UUID.        @rtype: list of strings.        @return: list of UUIDs        """        self.lock.acquire()        try:            return self.images.keys()        finally:            self.lock.release()    def free_space_bytes(self):        """Returns the amount of available space in KB.        @rtype: int        """        self.lock.acquire()        try:            return self.storage_free        finally:            self.lock.release()                def total_space_bytes(self):        """Returns the total usable space of the storage repo in KB.        @rtype: int        """        self.lock.acquire()        try:            if self.physical_size == XEND_STORAGE_NO_MAXIMUM:                stfs = os.statvfs(self.location)                return stfs.f_blocks * stfs.f_frsize            else:                return self.physical_size        finally:            self.lock.release()                def used_space_bytes(self):        """Returns the total amount of space used by this storage repository.        @rtype: int        """        self.lock.acquire()        try:            return self.physical_utilisation        finally:            self.lock.release()    def virtual_allocation(self):        """Returns the total virtual space allocated within the storage repo.        @rtype: int        """        self.lock.acquire()        try:            return self.virtual_allocation        finally:            self.lock.release()    def create_vdi(self, vdi_struct):        image_uuid = None        try:            size_bytes = int(vdi_struct.get('virtual_size', 0))            image_uuid = self._create_image_files(size_bytes)                        image = self.images[image_uuid]            image_cfg = {                'virtual_size': size_bytes,                'type': vdi_struct.get('type', 'system'),                'name_label': vdi_struct.get('name_label', ''),                'name_description': vdi_struct.get('name_description', ''),                'sharable': bool(vdi_struct.get('sharable', False)),                'read_only': bool(vdi_struct.get('read_only', False)),            }            # load in configuration from vdi_struct            image.load_config_dict(image_cfg)            # save configuration to file            cfg_filename =  XEND_STORAGE_VDICFG_FILENAME % image_uuid            cfg_path = os.path.join(self.location, cfg_filename)            image.save_config(cfg_path)                    except Exception, e:            # cleanup before raising exception            if image_uuid:                self.destroy_vdi(image_uuid)                            raise        return image_uuid

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -