def __validateConnectionParams(self, domType, conList): """ Validate connection parameters """ conParamsList = [] if domType in sd.FILE_DOMAIN_TYPES: paramInfos = PARAMS_FILE_DOMAIN elif domType in sd.BLOCK_DOMAIN_TYPES: paramInfos = PARAMS_BLOCK_DOMAIN else: raise se.InvalidParameterException("type", domType) for con in conList: conParams = {} for paramInfo in paramInfos: conParamName, paramName = paramInfo[:2] hasDefault = len(paramInfo) > 2 try: if hasDefault: value = con.get(paramName, paramInfo[2]) else: value = con[paramName] conParams[conParamName] = value except KeyError: raise se.InvalidParameterException( 'parameter "%s" is missing from connection info %s' % (paramName, con.get('id', ""))) conParamsList.append(conParams) return conParamsList
def _calculate_volume_alloc_size(cls, preallocate, capacity, initial_size): """ Calculate the allocation size in mb of the volume 'preallocate' - Sparse or Preallocated 'capacity' - the volume size in sectors 'initial_size' - optional, if provided the initial allocated size in sectors for sparse volumes """ if initial_size and initial_size > capacity: log.error( "The volume size %s is smaller " "than the requested initial size %s", capacity, initial_size) raise se.InvalidParameterException("initial size", initial_size) if initial_size and preallocate == volume.PREALLOCATED_VOL: log.error("Initial size is not supported for preallocated volumes") raise se.InvalidParameterException("initial size", initial_size) if preallocate == volume.SPARSE_VOL: if initial_size: initial_size = int(initial_size * QCOW_OVERHEAD_FACTOR) alloc_size = ((initial_size + SECTORS_TO_MB - 1) / SECTORS_TO_MB) else: alloc_size = config.getint("irs", "volume_utilization_chunk_mb") else: alloc_size = (capacity + SECTORS_TO_MB - 1) / SECTORS_TO_MB return alloc_size
def validateiSCSIParams(ip, port, username=None, password=None): if not ip: raise se.InvalidParameterException("IP", ip) else: try: ip = socket.gethostbyname(ip) except socket.gaierror: raise se.InvalidIpAddress(ip) if not port: raise se.InvalidParameterException("Port", port) return (ip, port, username, password)
def ddWatchCopy(src, dst, stop, size, offset=0, recoveryCallback=None): """ Copy src to dst using dd command with stop abilities """ try: size = int(size) except ValueError: raise se.InvalidParameterException("size", "size = %s" % (size,)) try: offset = int(offset) except ValueError: raise se.InvalidParameterException("offset", "offset = %s" % (offset,)) left = size baseoffset = offset while left > 0: (iounit, count, iooffset) = _alignData(left, offset) oflag = None conv = "notrunc" if (iounit % 512) == 0: if fileUtils.pathRequiresFlagForDirectIO(dst): oflag = DIRECTFLAG else: conv += ",%s" % DATASYNCFLAG cmd = [constants.EXT_DD, "if=%s" % src, "of=%s" % dst, "bs=%d" % iounit, "seek=%s" % iooffset, "skip=%s" % iooffset, "conv=%s" % conv, 'count=%s' % count] if oflag: cmd.append("oflag=%s" % oflag) if not stop: (rc, out, err) = execCmd(cmd, sudo=False, nice=utils.NICENESS.HIGH, ioclass=utils.IOCLASS.IDLE) else: (rc, out, err) = watchCmd(cmd, stop=stop, recoveryCallback=recoveryCallback, nice=utils.NICENESS.HIGH, ioclass=utils.IOCLASS.IDLE) if rc: raise se.MiscBlockWriteException(dst, offset, size) if not validateDDBytes(err, iounit * count): raise se.MiscBlockWriteIncomplete(dst, offset, size) left = left % iounit offset = baseoffset + size - left return (rc, out, err)
def __init__(self, repoPath, sdUUID, imgUUID, volUUID): self.repoPath = repoPath self.sdUUID = sdUUID self.imgUUID = imgUUID self.volUUID = volUUID self.volumePath = None self.imagePath = None if not imgUUID or imgUUID == BLANK_UUID: raise se.InvalidParameterException("imgUUID", imgUUID) if not volUUID or volUUID == BLANK_UUID: raise se.InvalidParameterException("volUUID", volUUID) self.voltype = None self.validate()
def _create(cls, dom, imgUUID, volUUID, size, volFormat, preallocate, volParent, srcImgUUID, srcVolUUID, volPath, initialSize=None): """ Class specific implementation of volumeCreate. All the exceptions are properly handled and logged in volume.create() """ if initialSize: cls.log.error("initialSize is not supported for file-based " "volumes") raise se.InvalidParameterException("initial size", initialSize) sizeBytes = size * BLOCK_SIZE truncSize = sizeBytes if volFormat == volume.RAW_FORMAT else 0 try: oop.getProcessPool(dom.sdUUID).truncateFile( volPath, truncSize, mode=VOLUME_PERMISSIONS, creatExcl=True) except OSError as e: if e.errno == errno.EEXIST: raise se.VolumeAlreadyExists(volUUID) raise if preallocate == volume.PREALLOCATED_VOL: try: # ddWatchCopy expects size to be in bytes misc.ddWatchCopy("/dev/zero", volPath, vars.task.aborting, sizeBytes) except ActionStopped: raise except Exception: cls.log.error("Unexpected error", exc_info=True) raise se.VolumesZeroingError(volPath) if not volParent: cls.log.info( "Request to create %s volume %s with size = %s " "sectors", volume.type2name(volFormat), volPath, size) if volFormat == volume.COW_FORMAT: qemuimg.create(volPath, sizeBytes, volume.fmt2str(volFormat)) else: # Create hardlink to template and its meta file cls.log.info("Request to create snapshot %s/%s of volume %s/%s", imgUUID, volUUID, srcImgUUID, srcVolUUID) volParent.clone(volPath, volFormat) # Forcing the volume permissions in case one of the tools we use # (dd, qemu-img, etc.) will mistakenly change the file permissiosn. dom.oop.os.chmod(volPath, VOLUME_PERMISSIONS) return (volPath, )
def validateDDBytes(ddstderr, size): log.debug("err: %s, size: %s" % (ddstderr, size)) try: size = int(size) except (ValueError, ): raise se.InvalidParameterException("size", str(size)) if len(ddstderr) != 3: raise se.InvalidParameterException("len(ddstderr)", ddstderr) try: xferred = int(ddstderr[2].split()[0]) except (ValueError, ): raise se.InvalidParameterException("ddstderr", ddstderr[2]) if xferred != size: return False return True
def create(cls, repoPath, sdUUID, imgUUID, size, volFormat, preallocate, diskType, volUUID, desc, srcImgUUID, srcVolUUID): """ Create a new volume with given size or snapshot 'size' - in sectors 'volFormat' - volume format COW / RAW 'preallocate' - Prealocate / Sparse 'diskType' - string that describes disk type System|Data|Shared|Swap|Temp 'srcImgUUID' - source image UUID 'srcVolUUID' - source volume UUID """ if not volUUID: volUUID = str(uuid.uuid4()) if volUUID == volume.BLANK_UUID: raise se.InvalidParameterException("volUUID", volUUID) # Validate volume parameters should be checked here for all # internal flows using volume creation. cls.validateCreateVolumeParams(volFormat, preallocate, srcVolUUID) mysd = sdCache.produce(sdUUID=sdUUID) try: lvm.getLV(sdUUID, volUUID) except se.LogicalVolumeDoesNotExistError: pass #OK, this is a new volume else: raise se.VolumeAlreadyExists(volUUID) imageDir = image.Image(repoPath).create(sdUUID, imgUUID) vol_path = os.path.join(imageDir, volUUID) pvol = None voltype = "LEAF" try: if srcVolUUID != volume.BLANK_UUID: # We have a parent if srcImgUUID == volume.BLANK_UUID: srcImgUUID = imgUUID pvol = BlockVolume(repoPath, sdUUID, srcImgUUID, srcVolUUID) # Cannot create snapshot for ILLEGAL volume if not pvol.isLegal(): raise se.createIllegalVolumeSnapshotError(pvol.volUUID) if imgUUID != srcImgUUID: pvol.share(imageDir, hard=False) pvol = BlockVolume(repoPath, sdUUID, imgUUID, srcVolUUID) # override size param by parent's size size = pvol.getSize() except se.StorageException: cls.log.error("Unexpected error", exc_info=True) raise except Exception, e: cls.log.error("Unexpected error", exc_info=True) raise se.VolumeCannotGetParent( "blockVolume can't get parent %s for volume %s: %s" % (srcVolUUID, volUUID, str(e)))
def validateUUID(uuid, name="uuid"): """ Ensure that uuid structure is 32 bytes long and is of the form: 8-4-4-4-12 (where each number depicts the amount of hex digits) Even though UUIDs can contain capital letters (because HEX strings are case insensitive) we usually compare uuids with the `==` operator, having uuids with upper case letters will cause unexpected bug so we filter them out """ m = UUID_REGEX.match(uuid) if m is None: raise se.InvalidParameterException(name, uuid) return True
def validateUUID(uuid, name="uuid", blank=True): """ Ensure that uuid structure is 32 bytes long and is of the form: 8-4-4-4-12 (where each number depicts the amount of hex digits) Even though UUIDs can contain capital letters (because HEX strings are case insensitive) we usually compare uuids with the `==` operator, having uuids with upper case letters will cause unexpected bug so we filter them out. The blank argument specifies if it's allowed for the uuid to be blank or not. """ try: m = UUID_REGEX.match(uuid) except TypeError: raise se.InvalidParameterException(name, uuid) if m is None: raise se.InvalidParameterException(name, uuid) if not blank and uuid == UUID_BLANK: raise se.InvalidParameterException(name, uuid)
def create(cls, repoPath, sdUUID, imgUUID, size, volFormat, preallocate, diskType, volUUID, desc, srcImgUUID, srcVolUUID): """ Create a new volume with given size or snapshot 'size' - in sectors 'volFormat' - volume format COW / RAW 'preallocate' - Prealocate / Sparse 'diskType' - string that describes disk type System|Data|Shared|Swap|Temp 'srcImgUUID' - source image UUID 'srcVolUUID' - source volume UUID """ if not volUUID: volUUID = str(uuid.uuid4()) if volUUID == volume.BLANK_UUID: raise se.InvalidParameterException("volUUID", volUUID) # Validate volume parameters should be checked here for all # internal flows using volume creation. cls.validateCreateVolumeParams(volFormat, preallocate, srcVolUUID) imageDir = image.Image(repoPath).create(sdUUID, imgUUID) vol_path = os.path.join(imageDir, volUUID) voltype = "LEAF" pvol = None # Check if volume already exists if oop.getProcessPool(sdUUID).fileUtils.pathExists(vol_path): raise se.VolumeAlreadyExists(vol_path) # Check if snapshot creation required if srcVolUUID != volume.BLANK_UUID: if srcImgUUID == volume.BLANK_UUID: srcImgUUID = imgUUID pvol = FileVolume(repoPath, sdUUID, srcImgUUID, srcVolUUID) # Cannot create snapshot for ILLEGAL volume if not pvol.isLegal(): raise se.createIllegalVolumeSnapshotError(pvol.volUUID) # create volume rollback vars.task.pushRecovery( task.Recovery("halfbaked volume rollback", "fileVolume", "FileVolume", "halfbakedVolumeRollback", [vol_path])) if preallocate == volume.PREALLOCATED_VOL: try: # ddWatchCopy expects size to be in bytes misc.ddWatchCopy("/dev/zero", vol_path, vars.task.aborting, (int(size) * 512)) except se.ActionStopped, e: raise e except Exception, e: cls.log.error("Unexpected error", exc_info=True) raise se.VolumesZeroingError(vol_path)
def validateSize(size, name): """ Validate number of bytes as string and convert to number of sectors, rounding up to next sectors. Raises InvalidParameterException if value is not a string or if it could not be converted to integer. """ if not isinstance(size, basestring): log.error("Number of sectors as int is not supported, use size in " "bytes as string") raise se.InvalidParameterException("size", size) size = validateN(size, name) return (size + SECTOR_SIZE - 1) / SECTOR_SIZE
def connect(self, domType, conList): """ Connect to a storage low level entity (server). """ self.log.info("Request to connect %s storage server", sd.type2name(domType)) conParams = self.__validateConnectionParams(domType, conList) if domType == sd.NFS_DOMAIN: return self.__connectFileServer(conParams, fileUtils.FSTYPE_NFS) elif domType == sd.LOCALFS_DOMAIN: return self.__connectLocalConnection(conParams) elif domType in sd.BLOCK_DOMAIN_TYPES: return self.__connectiSCSIServer(conParams) else: raise se.InvalidParameterException("type", domType)
def validate(self, domType, conList): """ Validate that we can connect to a storage server. """ self.log.info("Request to validate %s storage server", sd.type2name(domType)) conParams = self.__validateConnectionParams(domType, conList) if domType == sd.NFS_DOMAIN: return self.__validateFileServer(conParams, fileUtils.FSTYPE_NFS) elif domType == sd.LOCALFS_DOMAIN: return self.__validateLocalConnection(conParams) elif domType in sd.BLOCK_DOMAIN_TYPES: return self.__validateiSCSIConnection(conParams) else: raise se.InvalidParameterException("type", domType)
def validateN(number, name): n = validateInt(number, name) if n < 0: raise se.InvalidParameterException(name, number) return n
def validateID(cls, taskID): if not taskID or "." in taskID: raise se.InvalidParameterException("taskID", taskID)
def validateInt(number, name): try: return int(number) except: raise se.InvalidParameterException(name, number)
def validateInt(number, name): #FIXME: Consider using confutils validator? try: return int(number) except: raise se.InvalidParameterException(name, number)