def __enter__(self): if self.exists_lock < self.target_lock: active_lv(self.abs_path, self.shared) if linux.qcow2_get_backing_file(self.abs_path) != "": self.backing = RecursiveOperateLv(linux.qcow2_get_backing_file(self.abs_path), True, False) if self.backing is not None: self.backing.__enter__()
def __enter__(self): if self.exists_lock < self.target_lock: active_lv(self.abs_path, self.shared) if linux.qcow2_get_backing_file(self.abs_path) != "": self.backing = RecursiveOperateLv( linux.qcow2_get_backing_file(self.abs_path), True, self.skip_deactivate_tags, False) if self.backing is not None: self.backing.__enter__()
def rebase_volume_backing_file(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = NfsRebaseVolumeBackingFileRsp() if not cmd.dstImageCacheTemplateFolderPath: qcow2s = shell.call("find %s -type f -regex '.*\.qcow2$'" % cmd.dstVolumeFolderPath) else: qcow2s = shell.call("find %s %s -type f -regex '.*\.qcow2$'" % (cmd.dstVolumeFolderPath, cmd.dstImageCacheTemplateFolderPath)) for qcow2 in qcow2s.split(): fmt = shell.call("qemu-img info %s | grep '^file format' | awk -F ': ' '{ print $2 }'" % qcow2) if fmt.strip() != "qcow2": continue backing_file = linux.qcow2_get_backing_file(qcow2) if backing_file == "": continue # actions like `create snapshot -> recover snapshot -> delete snapshot` may produce garbage qcow2, whose backing file doesn't exist new_backing_file = backing_file.replace(cmd.srcPsMountPath, cmd.dstPsMountPath) if not os.path.exists(new_backing_file): logger.debug("the backing file[%s] of volume[%s] doesn't exist, skip rebasing" % (new_backing_file, qcow2)) continue linux.qcow2_rebase_no_check(new_backing_file, qcow2) return jsonobject.dumps(rsp)
def rebase_volume_backing_file(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = NfsRebaseVolumeBackingFileRsp() if not cmd.dstImageCacheTemplateFolderPath: qcow2s = shell.call("find %s -type f -regex '.*\.qcow2$'" % cmd.dstVolumeFolderPath) else: qcow2s = shell.call( "find %s %s -type f -regex '.*\.qcow2$'" % (cmd.dstVolumeFolderPath, cmd.dstImageCacheTemplateFolderPath)) for qcow2 in qcow2s.split(): fmt = shell.call( "qemu-img info %s | grep '^file format' | awk -F ': ' '{ print $2 }'" % qcow2) if fmt.strip() != "qcow2": continue backing_file = linux.qcow2_get_backing_file(qcow2) if backing_file == "": continue new_backing_file = backing_file.replace(cmd.srcPsMountPath, cmd.dstPsMountPath) linux.qcow2_rebase_no_check(new_backing_file, qcow2) return jsonobject.dumps(rsp)
def migrate_volumes(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = AgentRsp() for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.OperateLv(current_abs_path, shared=True): virtual_size = lvm.get_lv_size(current_abs_path) if lvm.lv_exists(target_abs_path): target_ps_uuid = get_primary_storage_uuid_from_install_path(struct.targetInstallPath) raise Exception("found %s already exists on ps %s" % (target_abs_path, target_ps_uuid)) lvm.create_lv_from_absolute_path(target_abs_path, virtual_size, "%s::%s::%s" % (VOLUME_TAG, cmd.hostUuid, time.time())) lvm.active_lv(target_abs_path, lvm.LvmlockdLockType.SHARE) try: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.OperateLv(current_abs_path, shared=True): bash.bash_errorout("cp %s %s" % (current_abs_path, target_abs_path)) for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.RecursiveOperateLv(current_abs_path, shared=True): previous_ps_uuid = get_primary_storage_uuid_from_install_path(struct.currentInstallPath) target_ps_uuid = get_primary_storage_uuid_from_install_path(struct.targetInstallPath) current_backing_file = linux.qcow2_get_backing_file(current_abs_path) # type: str target_backing_file = current_backing_file.replace(previous_ps_uuid, target_ps_uuid) if current_backing_file is not None and current_backing_file != "": lvm.do_active_lv(target_backing_file, lvm.LvmlockdLockType.SHARE, False) logger.debug("rebase %s to %s" % (target_abs_path, target_backing_file)) linux.qcow2_rebase_no_check(target_backing_file, target_abs_path) if struct.compareQcow2: bash.bash_errorout("time qemu-img compare %s %s" % (current_abs_path, target_abs_path)) except Exception as e: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) if struct.currentInstallPath == struct.targetInstallPath: logger.debug("current install path %s equals target %s, skip to delete" % (struct.currentInstallPath, struct.targetInstallPath)) else: logger.debug("error happened, delete lv %s" % target_abs_path) lvm.delete_lv(target_abs_path, False) raise e finally: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) lvm.deactive_lv(target_abs_path) rsp.totalCapacity, rsp.availableCapacity = lvm.get_vg_size(cmd.vgUuid) return jsonobject.dumps(rsp)
def get_backing_file_path(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) out = linux.qcow2_get_backing_file(cmd.path) rsp = GetBackingFileRsp() if out: rsp.backingFilePath = out rsp.size = os.path.getsize(out) return jsonobject.dumps(rsp)
def get_backing_file_path(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) out = linux.qcow2_get_backing_file(cmd.path) rsp = GetBackingFileRsp() if out: rsp.backingFilePath = out rsp.size = os.path.getsize(out) return jsonobject.dumps(rsp)
def do_active_lv(absolutePath, lockType, recursive): def handle_lv(lockType, fpath): if lockType > LvmlockdLockType.NULL: active_lv(fpath, lockType == LvmlockdLockType.SHARE) else: deactive_lv(fpath) handle_lv(lockType, absolutePath) if recursive is False or lockType is LvmlockdLockType.NULL: return while linux.qcow2_get_backing_file(absolutePath) != "": absolutePath = linux.qcow2_get_backing_file(absolutePath) if lockType == LvmlockdLockType.NULL: handle_lv(LvmlockdLockType.NULL, absolutePath) else: # activate backing files only in shared mode handle_lv(LvmlockdLockType.SHARE, absolutePath)
def do_active_lv(absolutePath, lockType, recursive): def handle_lv(lockType, fpath): if lockType > LvmlockdLockType.NULL: active_lv(fpath, lockType == LvmlockdLockType.SHARE) else: deactive_lv(fpath) handle_lv(lockType, absolutePath) if recursive is False or lockType is LvmlockdLockType.NULL: return while linux.qcow2_get_backing_file(absolutePath) != "": absolutePath = linux.qcow2_get_backing_file(absolutePath) if lockType == LvmlockdLockType.NULL: handle_lv(LvmlockdLockType.NULL, absolutePath) else: # activate backing files only in shared mode handle_lv(LvmlockdLockType.SHARE, absolutePath)
def do_active_lv(self, installPath, lockType, recursive): def handle_lv(lockType, fpath): if lockType > lvm.LvmlockdLockType.NULL: lvm.active_lv(fpath, lockType == lvm.LvmlockdLockType.SHARE) else: lvm.deactive_lv(fpath) install_abs_path = translate_absolute_path_from_install_path(installPath) handle_lv(lockType, install_abs_path) if recursive is False or lockType is lvm.LvmlockdLockType.NULL: return while linux.qcow2_get_backing_file(install_abs_path) != "": install_abs_path = linux.qcow2_get_backing_file(install_abs_path) if lockType == lvm.LvmlockdLockType.NULL: handle_lv(lvm.LvmlockdLockType.NULL, install_abs_path) else: # activate backing files only in shared mode handle_lv(lvm.LvmlockdLockType.SHARE, install_abs_path)
def do_active_lv(self, installPath, lockType, recursive): def handle_lv(lockType, fpath): if lockType > lvm.LvmlockdLockType.NULL: lvm.active_lv(fpath, lockType == lvm.LvmlockdLockType.SHARE) else: lvm.deactive_lv(fpath) install_abs_path = translate_absolute_path_from_install_path(installPath) handle_lv(lockType, install_abs_path) if recursive is False or lockType is lvm.LvmlockdLockType.NULL: return while linux.qcow2_get_backing_file(install_abs_path) != "": install_abs_path = linux.qcow2_get_backing_file(install_abs_path) if lockType == lvm.LvmlockdLockType.NULL: handle_lv(lvm.LvmlockdLockType.NULL, install_abs_path) else: # activate backing files only in shared mode handle_lv(lvm.LvmlockdLockType.SHARE, install_abs_path)
def get_qcow2_reference(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) out = shell.call('find %s -type f' % cmd.searchingDir) rsp = GetQCOW2ReferenceRsp() rsp.referencePaths = [] real_path = os.path.realpath(cmd.path) for f in out.splitlines(): backing_file = linux.qcow2_get_backing_file(f) if os.path.realpath(backing_file) == real_path: rsp.referencePaths.append(f) return jsonobject.dumps(rsp)
def get_qcow2_reference(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) out = shell.call('find %s -type f' % cmd.searchingDir) rsp = GetQCOW2ReferenceRsp() rsp.referencePaths = [] real_path = os.path.realpath(cmd.path) for f in out.splitlines(): backing_file = linux.qcow2_get_backing_file(f) if os.path.realpath(backing_file) == real_path: rsp.referencePaths.append(f) return jsonobject.dumps(rsp)
def do_active_lv(self, installPath, lockType, recursive, killProcess=False): def handle_lv(lockType, fpath): if lockType > lvm.LvmlockdLockType.NULL: lvm.active_lv(fpath, lockType == lvm.LvmlockdLockType.SHARE) else: try: lvm.deactive_lv(fpath) except Exception as e: if not killProcess: return qemus = lvm.find_qemu_for_lv_in_use(fpath) if len(qemus) == 0: return for qemu in qemus: if qemu.state != "running": linux.kill_process(qemu.pid) lvm.deactive_lv(fpath) install_abs_path = translate_absolute_path_from_install_path( installPath) handle_lv(lockType, install_abs_path) if recursive is False or lockType is lvm.LvmlockdLockType.NULL: return while linux.qcow2_get_backing_file(install_abs_path) != "": install_abs_path = linux.qcow2_get_backing_file(install_abs_path) if lockType == lvm.LvmlockdLockType.NULL: handle_lv(lvm.LvmlockdLockType.NULL, install_abs_path) else: # activate backing files only in shared mode handle_lv(lvm.LvmlockdLockType.SHARE, install_abs_path)
def verify_backing_file_chain(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) for sp in cmd.snapshots: if not os.path.exists(sp.path): raise Exception('cannot find the file[%s]' % sp.path) if sp.parentPath and not os.path.exists(sp.parentPath): raise Exception('cannot find the backing file[%s]' % sp.parentPath) if sp.parentPath: out = linux.qcow2_get_backing_file(sp.path) if sp.parentPath != out: raise Exception("resource[Snapshot or Volume, uuid:%s, path:%s]'s backing file[%s] is not equal to %s" % (sp.snapshotUuid, sp.path, out, sp.parentPath)) return jsonobject.dumps(AgentResponse())
def verify_backing_file_chain(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) for sp in cmd.snapshots: if not os.path.exists(sp.path): raise Exception('cannot find the file[%s]' % sp.path) if sp.parentPath and not os.path.exists(sp.parentPath): raise Exception('cannot find the backing file[%s]' % sp.parentPath) if sp.parentPath: out = linux.qcow2_get_backing_file(sp.path) if sp.parentPath != out: raise Exception( "resource[Snapshot or Volume, uuid:%s, path:%s]'s backing file[%s] is not equal to %s" % (sp.snapshotUuid, sp.path, out, sp.parentPath)) return jsonobject.dumps(AgentResponse())
def rebase_volume_backing_file(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = NfsRebaseVolumeBackingFileRsp() if not cmd.dstImageCacheTemplateFolderPath: qcow2s = shell.call("find %s -type f -regex '.*\.qcow2$'" % cmd.dstVolumeFolderPath) else: qcow2s = shell.call("find %s %s -type f -regex '.*\.qcow2$'" % (cmd.dstVolumeFolderPath, cmd.dstImageCacheTemplateFolderPath)) for qcow2 in qcow2s.split(): fmt = shell.call("qemu-img info %s | grep '^file format' | awk -F ': ' '{ print $2 }'" % qcow2) if fmt.strip() != "qcow2": continue backing_file = linux.qcow2_get_backing_file(qcow2) if backing_file == "": continue new_backing_file = backing_file.replace(cmd.srcPsMountPath, cmd.dstPsMountPath) linux.qcow2_rebase_no_check(new_backing_file, qcow2) return jsonobject.dumps(rsp)
def get_qcow2_reference(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = GetQCOW2ReferenceRsp() rsp.referencePaths = [] real_path = get_absolute_path_from_install_path(cmd.path) for f in lvm.list_local_active_lvs(cmd.vgUuid): backing_file = linux.qcow2_direct_get_backing_file(f) if backing_file == real_path: rsp.referencePaths.append(f) for f in bash.bash_o( "ls -l /dev/drbd* | grep -E '^b' | awk '{print $NF}'" ).splitlines(): f = f.strip() if f == "": continue try: if linux.qcow2_get_backing_file(f) == real_path: rsp.referencePaths.append(f) except IOError: continue logger.debug("find qcow2 %s referencess: %s" % (real_path, rsp.referencePaths)) return jsonobject.dumps(rsp)
def migrate_volumes(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = AgentRsp() for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.OperateLv(current_abs_path, shared=True): lv_size = lvm.get_lv_size(current_abs_path) if lvm.lv_exists(target_abs_path): target_ps_uuid = get_primary_storage_uuid_from_install_path(struct.targetInstallPath) raise Exception("found %s already exists on ps %s" % (target_abs_path, target_ps_uuid)) lvm.create_lv_from_absolute_path(target_abs_path, lvm.getOriginalSize(lv_size), "%s::%s::%s" % (VOLUME_TAG, cmd.hostUuid, time.time())) lvm.active_lv(target_abs_path, lvm.LvmlockdLockType.SHARE) try: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.OperateLv(current_abs_path, shared=True): bash.bash_errorout("cp %s %s" % (current_abs_path, target_abs_path)) for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) current_abs_path = translate_absolute_path_from_install_path(struct.currentInstallPath) with lvm.RecursiveOperateLv(current_abs_path, shared=True): previous_ps_uuid = get_primary_storage_uuid_from_install_path(struct.currentInstallPath) target_ps_uuid = get_primary_storage_uuid_from_install_path(struct.targetInstallPath) current_backing_file = linux.qcow2_get_backing_file(current_abs_path) # type: str target_backing_file = current_backing_file.replace(previous_ps_uuid, target_ps_uuid) if struct.compareQcow2: logger.debug("comparing qcow2 between %s and %s" % (current_abs_path, target_abs_path)) if not self.compare(current_abs_path, target_abs_path): raise Exception("qcow2 %s and %s are not identical" % (current_abs_path, target_abs_path)) logger.debug("confirmed qcow2 %s and %s are identical" % (current_abs_path, target_abs_path)) if current_backing_file is not None and current_backing_file != "": lvm.do_active_lv(target_backing_file, lvm.LvmlockdLockType.SHARE, False) logger.debug("rebase %s to %s" % (target_abs_path, target_backing_file)) linux.qcow2_rebase_no_check(target_backing_file, target_abs_path) except Exception as e: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) if struct.currentInstallPath == struct.targetInstallPath: logger.debug("current install path %s equals target %s, skip to delete" % (struct.currentInstallPath, struct.targetInstallPath)) else: logger.debug("error happened, delete lv %s" % target_abs_path) lvm.delete_lv(target_abs_path, False) raise e finally: for struct in cmd.migrateVolumeStructs: target_abs_path = translate_absolute_path_from_install_path(struct.targetInstallPath) lvm.deactive_lv(target_abs_path) rsp.totalCapacity, rsp.availableCapacity = lvm.get_vg_size(cmd.vgUuid) return jsonobject.dumps(rsp)
def activate_and_remove(f): active_lv(f, shared=False) backing = linux.qcow2_get_backing_file(f) shell.check_run("lvremove -y -Stags={%s} %s" % (tag, f)) return f
def stream_body(task, fpath, entity, boundary): def _progress_consumer(total): task.downloadedSize = total @thread.AsyncThread def _do_import(task, fpath): shell.check_run("cat %s | rbd import --image-format 2 - %s" % (fpath, task.tmpPath)) while True: headers = cherrypy._cpreqbody.Part.read_headers(entity.fp) p = CustomPart(entity.fp, headers, boundary, fpath, _progress_consumer) if not p.filename: continue # start consumer _do_import(task, fpath) try: p.process() except Exception as e: logger.warn('process image %s failed: %s' % (task.imageUuid, str(e))) pass finally: if p.wfd is not None: p.wfd.close() break if task.downloadedSize != task.expectedSize: task.fail('incomplete upload, got %d, expect %d' % (task.downloadedSize, task.expectedSize)) shell.run('rbd rm %s' % task.tmpPath) return file_format = None try: file_format = linux.get_img_fmt('rbd:' + task.tmpPath) except Exception as e: task.fail('upload image %s failed: %s' % (task.imageUuid, str(e))) return if file_format == 'qcow2': if linux.qcow2_get_backing_file('rbd:' + task.tmpPath): task.fail('Qcow2 image %s has backing file' % task.imageUuid) shell.run('rbd rm %s' % task.tmpPath) return conf_path = None try: with open('/etc/ceph/ceph.conf', 'r') as fd: conf = fd.read() conf = '%s\n%s\n' % (conf, 'rbd default format = 2') conf_path = linux.write_to_temp_file(conf) shell.check_run('%s -f qcow2 -O rbd rbd:%s rbd:%s:conf=%s' % (qemu_img.subcmd('convert'), task.tmpPath, task.dstPath, conf_path)) except Exception as e: task.fail('cannot convert Qcow2 image %s to rbd' % task.imageUuid) logger.warn('convert image %s failed: %s', (task.imageUuid, str(e))) return finally: shell.run('rbd rm %s' % task.tmpPath) if conf_path: os.remove(conf_path) else: shell.check_run('rbd mv %s %s' % (task.tmpPath, task.dstPath)) task.success()
def activate_and_remove(f): active_lv(f, shared=False) backing = linux.qcow2_get_backing_file(f) shell.check_run("lvremove -y -Stags={%s} %s" % (tag, f)) return f
def stream_body(task, fpath, entity, boundary): def _progress_consumer(total): task.downloadedSize = total @thread.AsyncThread def _do_import(task, fpath): shell.check_run("cat %s | rbd import --image-format 2 - %s" % (fpath, task.tmpPath)) while True: headers = cherrypy._cpreqbody.Part.read_headers(entity.fp) p = CustomPart(entity.fp, headers, boundary, fpath, _progress_consumer) if not p.filename: continue # start consumer _do_import(task, fpath) try: p.process() except Exception as e: logger.warn('process image %s failed: %s' % (task.imageUuid, str(e))) pass finally: if p.wfd is not None: p.wfd.close() break if task.downloadedSize != task.expectedSize: task.fail('incomplete upload, got %d, expect %d' % (task.downloadedSize, task.expectedSize)) shell.run('rbd rm %s' % task.tmpPath) return file_format = None try: file_format = linux.get_img_fmt('rbd:'+task.tmpPath) except Exception as e: task.fail('upload image %s failed: %s' % (task.imageUuid, str(e))) return if file_format == 'qcow2': if linux.qcow2_get_backing_file('rbd:'+task.tmpPath): task.fail('Qcow2 image %s has backing file' % task.imageUuid) shell.run('rbd rm %s' % task.tmpPath) return conf_path = None try: with open('/etc/ceph/ceph.conf', 'r') as fd: conf = fd.read() conf = '%s\n%s\n' % (conf, 'rbd default format = 2') conf_path = linux.write_to_temp_file(conf) shell.check_run('qemu-img convert -f qcow2 -O rbd rbd:%s rbd:%s:conf=%s' % (task.tmpPath, task.dstPath, conf_path)) except Exception as e: task.fail('cannot convert Qcow2 image %s to rbd' % task.imageUuid) logger.warn('convert image %s failed: %s', (task.imageUuid, str(e))) return finally: shell.run('rbd rm %s' % task.tmpPath) if conf_path: os.remove(conf_path) else: shell.check_run('rbd mv %s %s' % (task.tmpPath, task.dstPath)) task.success()