def create_template_from_volume(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = AgentRsp() volume_abs_path = translate_absolute_path_from_install_path( cmd.volumePath) install_abs_path = translate_absolute_path_from_install_path( cmd.installPath) if cmd.sharedVolume: lvm.do_active_lv(volume_abs_path, lvm.LvmlockdLockType.SHARE, True) with lvm.RecursiveOperateLv(volume_abs_path, shared=cmd.sharedVolume, skip_deactivate_tag=IMAGE_TAG): virtual_size = linux.qcow2_virtualsize(volume_abs_path) if not lvm.lv_exists(install_abs_path): lvm.create_lv_from_absolute_path( install_abs_path, virtual_size, "%s::%s::%s" % (VOLUME_TAG, cmd.hostUuid, time.time())) with lvm.OperateLv(install_abs_path, shared=False, delete_when_exception=True): linux.create_template(volume_abs_path, install_abs_path) logger.debug( 'successfully created template[%s] from volume[%s]' % (cmd.installPath, cmd.volumePath)) if cmd.compareQcow2 is True: logger.debug("comparing qcow2 between %s and %s") bash.bash_errorout("time qemu-img compare %s %s" % (volume_abs_path, install_abs_path)) logger.debug("confirmed qcow2 %s and %s are identical" % (volume_abs_path, install_abs_path)) rsp.totalCapacity, rsp.availableCapacity = lvm.get_vg_size(cmd.vgUuid) return jsonobject.dumps(rsp)
def install_drbd(): mod_installed = bash.bash_r("lsmod | grep drbd") == 0 mod_exists = bash.bash_r("modinfo drbd") == 0 utils_installed = bash.bash_r( "rpm -ql drbd-utils || rpm -ql drbd84-utils") == 0 basearch = platform.machine() releasever = bash.bash_o("awk '{print $3}' /etc/zstack-release") utils_exists, o = bash.bash_ro( "ls /opt/zstack-dvd/{}/{}/Packages/drbd-utils*".format( basearch, releasever)) if mod_installed and utils_exists: return if not mod_installed: if mod_exists: bash.bash_errorout("modprobe drbd") else: raise Exception("drbd mod not installed and not exists!") if not utils_installed: if utils_exists == 0: bash.bash_errorout("rpm -ivh %s" % o) else: raise Exception("drbd utils not installed and not exists!")
def create_template_from_volume(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = AgentRsp() volume_abs_path = translate_absolute_path_from_install_path(cmd.volumePath) install_abs_path = translate_absolute_path_from_install_path(cmd.installPath) if cmd.sharedVolume: lvm.do_active_lv(volume_abs_path, lvm.LvmlockdLockType.SHARE, True) with lvm.RecursiveOperateLv(volume_abs_path, shared=cmd.sharedVolume, skip_deactivate_tags=[IMAGE_TAG]): virtual_size = linux.qcow2_virtualsize(volume_abs_path) total_size = 0 for qcow2 in linux.qcow2_get_file_chain(volume_abs_path): total_size += int(lvm.get_lv_size(qcow2)) if total_size > virtual_size: total_size = virtual_size if not lvm.lv_exists(install_abs_path): lvm.create_lv_from_absolute_path(install_abs_path, total_size, "%s::%s::%s" % (VOLUME_TAG, cmd.hostUuid, time.time())) with lvm.OperateLv(install_abs_path, shared=False, delete_when_exception=True): linux.create_template(volume_abs_path, install_abs_path) logger.debug('successfully created template[%s] from volume[%s]' % (cmd.installPath, cmd.volumePath)) if cmd.compareQcow2 is True: logger.debug("comparing qcow2 between %s and %s") bash.bash_errorout("time qemu-img compare %s %s" % (volume_abs_path, install_abs_path)) logger.debug("confirmed qcow2 %s and %s are identical" % (volume_abs_path, install_abs_path)) rsp.totalCapacity, rsp.availableCapacity = lvm.get_vg_size(cmd.vgUuid) return jsonobject.dumps(rsp)
def add_pv(vg_uuid, disk_path, metadata_size): bash.bash_errorout("vgextend --metadatasize %s %s %s" % (metadata_size, vg_uuid, disk_path)) if bash.bash_r("pvs --nolocking --readonly %s | grep %s" % (disk_path, vg_uuid)): raise Exception("disk %s not added to vg %s after vgextend" % (disk_path, vg_uuid))
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 active_lv(path, shared=False): flag = "-ay" if shared: flag = "-asy" bash.bash_errorout("lvchange %s %s" % (flag, path)) if lv_is_active(path) is False: raise Exception("active lv %s with %s failed" % (path, flag))
def dd_out(self, dst_path, sparse=True): need_promte_first = self.get_role() == DrbdRole.Secondary need_promte_first and self.promote() try: bash.bash_errorout('dd if=%s of=%s bs=1M %s' % (self.get_dev_path(), dst_path, 'conv=sparse' if sparse else '')) finally: need_promte_first and self.demote()
def deactive_lv(path, raise_exception=True): if not lv_exists(path): return if not lv_is_active(path): return if raise_exception: bash.bash_errorout("lvchange -an %s" % path) else: bash.bash_r("lvchange -an %s" % path) if lv_is_active(path): raise RetryException("lv %s is still active after lvchange -an" % path)
def create_lv_from_absolute_path(path, size, tag="zs::sharedblock::volume"): vgName = path.split("/")[2] lvName = path.split("/")[3] bash.bash_errorout("lvcreate -an --addtag %s --size %sb --name %s %s" % (tag, calcLvReservedSize(size), lvName, vgName)) if not lv_exists(path): raise Exception("can not find lv %s after create", path) with OperateLv(path, shared=False): dd_zero(path)
def create_thin_pool_if_not_found(vgUuid, init_pool_ratio): def round_sector(size, sector): return round(float(size) / float(sector)) * sector if lvm.lv_exists("/dev/%s/%s_thinpool" % (vgUuid, vgUuid)): return tot, avil = lvm.get_vg_size(vgUuid) init_pool_size = float(tot) * float(init_pool_ratio) # meta_size = "%s" % ((tot / DEFAULT_CHUNK_SIZE) * 48 * 2) # ref: https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt meta_size = 1024**3 # ref: https://www.systutorials.com/docs/linux/man/7-lvmthin/#lbBD bash.bash_errorout( "lvcreate --type thin-pool -L %sB -c %sB --poolmetadatasize %sB -n %s_thinpool %s" % (int(round_sector(init_pool_size, 4096)), DEFAULT_CHUNK_SIZE, meta_size, vgUuid, vgUuid))
def promote(self, force=False, retry=60, sleep=2): @bash.in_bash @linux.retry(times=retry, sleep_time=sleep) def do_promote(): f = " --force" if force else "" r, o, e = bash.bash_roe("drbdadm primary %s %s" % (self.name, f)) if self.get_role() != DrbdRole.Primary: raise RetryException( "promote failed, return: %s, %s, %s. resource %s still not in role %s" % (r, o, e, self.name, DrbdRole.Primary)) if not force: do_promote() else: bash.bash_errorout("drbdadm primary %s --force" % self.name)
def initialize(self, primary, cmd, backing=None, skip_clear_bits=False): bash.bash_errorout("echo yes | drbdadm create-md %s" % self.name) self.up() if skip_clear_bits: return if not primary: self.clear_bits() else: self.promote() if backing: linux.qcow2_create_with_backing_file_and_cmd( backing, self.get_dev_path(), cmd) else: linux.qcow2_create_with_cmd(self.get_dev_path(), cmd.size, cmd) self.demote()
def run_self_test(busNumber, deviceNumber, wwn): @linux.retry(10, 1) @bash.in_bash def self_test_is_running(bus, device): r = bash.bash_r( "smartctl -l selftest -d megaraid,%s /dev/bus/%s | grep 'Self-test routine in progress'" % (device, bus)) if r == 0: return r, o, e = bash.bash_roe("smartctl -a /dev/bus/%s -d megaraid,%s" % (bus, device)) if "Self-test routine in progress" in o + e: return raise RetryException( "can not find self test in progress on drive %s" % wwn) @linux.retry(10, 30) @bash.in_bash def get_self_test_result(bus, device): r, o = bash.bash_ro( "smartctl -l selftest -d megaraid,%s /dev/bus/%s | grep -E '^# 1'" % (device, bus)) if r != 0 or "00%" not in o: raise RetryException( "latest self test not finished on drive %s" % wwn) return o.split("Short offline")[1].split("00%")[0].strip() @bash.in_bash def check_no_running_test(bus, device): r, o = bash.bash_ro( "smartctl -a /dev/bus/%s -d megaraid,%s | grep 'Self-test routine in progress' -C 5" % (bus, device)) if r == 0: return False return True for i in range(5): if check_no_running_test(busNumber, deviceNumber) is True: break if i == 4: # bash.bash_r("smartctl -X /dev/bus/%s -d megaraid,%s") raise Exception("there is running test on drive wwn %s" % wwn) time.sleep(30) bash.bash_errorout("smartctl --test=short /dev/bus/%s -d megaraid,%s" % (busNumber, deviceNumber)) self_test_is_running(busNumber, deviceNumber) return get_self_test_result(busNumber, deviceNumber)
def lv_rename(old_abs_path, new_abs_path, overwrite=False): if not lv_exists(new_abs_path): return bash.bash_roe("lvrename %s %s" % (old_abs_path, new_abs_path)) if overwrite is False: raise Exception("lv with name %s is already exists, can not rename lv %s to it" % (new_abs_path, old_abs_path)) tmp_path = new_abs_path + "_%s" % int(time.time()) r, o, e = lv_rename(new_abs_path, tmp_path) if r != 0: raise Exception("rename lv %s to tmp name %s failed: stdout: %s, stderr: %s" % (new_abs_path, tmp_path, o, e)) r, o, e = lv_rename(old_abs_path, new_abs_path) if r != 0: bash.bash_errorout("lvrename %s %s" % (tmp_path, new_abs_path)) raise Exception("rename lv %s to tmp name %s failed: stdout: %s, stderr: %s" % (old_abs_path, new_abs_path, o, e)) delete_lv(tmp_path, False)
def install_drbd(): mod_installed = bash.bash_r("lsmod | grep drbd") == 0 mod_exists = bash.bash_r("modinfo drbd") == 0 utils_installed = bash.bash_r( "rpm -ql drbd-utils || rpm -ql drbd84-utils") == 0 utils_exists, o = bash.bash_ro("ls /opt/zstack-dvd/Packages/drbd-utils*") if mod_installed and utils_exists: return if not mod_installed: if mod_exists: bash.bash_errorout("modprobe drbd") else: raise Exception("drbd mod not installed and not exists!") if not utils_installed: if utils_exists == 0: bash.bash_errorout("rpm -ivh %s" % o) else: raise Exception("drbd utils not installed and not exists!")
def delete_lv(path, raise_exception=True): logger.debug("deleting lv %s" % path) # remove meta-lv if any if lv_exists(get_meta_lv_path(path)): shell.run("lvremove -y %s" % get_meta_lv_path(path)) if not lv_exists(path): return if raise_exception: o = bash.bash_errorout("lvremove -y %s" % path) else: o = bash.bash_o("lvremove -y %s" % path) return o
def initialize_with_file(self, primary, src_path, backing=None, backing_fmt=None, skip_clear_bits=False): bash.bash_errorout("echo yes | drbdadm create-md %s --force" % self.name) self.up() if skip_clear_bits: return if not primary: self.clear_bits() else: self.promote() bash.bash_errorout('dd if=%s of=%s bs=1M oflag=direct' % (src_path, self.get_dev_path())) if backing: linux.qcow2_rebase_no_check(backing, self.get_dev_path(), backing_fmt=backing_fmt) self.demote()
def raid_locate(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = AgentRsp() r, raid_info, e = bash.bash_roe( "/opt/MegaRAID/MegaCli/MegaCli64 -LdPdInfo -aALL") if r != 0: raise Exception( "can not execute MegaCli: returnCode: %s, stdout: %s, stderr: %s" % (r, raid_info, e)) drive = self.get_raid_device_info( "/dev/bus/%d -d megaraid,%d" % (cmd.busNumber, cmd.deviceNumber), raid_info) if drive.wwn != cmd.wwn: raise Exception( "expect drive[busNumber %s, deviceId %s, slotNumber %s] wwn is %s, but is %s actually" % (cmd.busNumber, cmd.deviceNumber, cmd.slotNumber, cmd.wwn, drive.wwn)) command = "start" if cmd.locate is True else "stop" bash.bash_errorout( "/opt/MegaRAID/MegaCli/MegaCli64 -PdLocate -%s -physdrv[%d:%d] -a%d" % (command, cmd.enclosureDeviceID, cmd.slotNumber, cmd.busNumber)) 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 up(self): if not self.minor_allocated() or self.get_cstate( ) == DrbdNetState.Unconfigured: bash.bash_errorout("drbdadm up %s" % self.name)
def do_demote(): bash.bash_errorout("drbdadm secondary %s" % self.name)
def clear_bits(self): bash.bash_errorout("drbdadm new-current-uuid --clear-bitmap %s" % self.name)
def resize(self): bash.bash_errorout("drbdadm -- --assume-clean resize %s" % self.name)