Beispiel #1
0
    def test_get_replies_state(self):
        # 正常存储池
        msg = LinstorAPI().get_linstorapi().storage_pool_list(['vince2'], ['pool_a'])[0]
        assert LinstorAPI().get_replies_state(msg.storage_pools[0].reports) == 'Ok'


        # 存储池warining
        msg = LinstorAPI().get_linstorapi().storage_pool_list(['ubuntu'],['pool_b'])[0]
        for storpool in msg.storage_pools:
            assert LinstorAPI().get_replies_state(storpool.reports) == 'Warning'
Beispiel #2
0
    def test_parse_size_str(self):
        # 1048576KB == 1GB
        assert LinstorAPI().parse_size_str('1G') == 1048576

        # size不为字符串
        with pytest.raises(SystemExit) as attrex:
            LinstorAPI().parse_size_str('asdkjsad')
        assert attrex.type == SystemExit

        # size单位异常
        with pytest.raises(SystemExit) as attrex:
            LinstorAPI().parse_size_str('10SDLJ')
        assert attrex.type == SystemExit
Beispiel #3
0
    def __init__(self, node):
        try:
            self.api = LinstorAPI()
            self.sp = self.api.get_storagepool([node])
            self.res = self.api.get_resource([node])
        except AttributeError:
            self.sp = None
            self.res = None

        if node == utils.get_hostname():
            self.conn = None
        else:
            self.conn = utils.SSHConn(node)

        self.pv_list = self.get_pvs()
        self.vg_list = self.get_vgs()
        self.lv_list = self.get_lvs()
Beispiel #4
0
    def test_get_linstorapi(self):
        # 正常情况下
        assert LinstorAPI().get_linstorapi() is not None

        # 关闭linstor连接
        os.system('systemctl stop linstor-controller')
        time.sleep(2)

        # linstor未连接的情况下
        with pytest.raises(linstor.LinstorNetworkError) as neterr:
            LinstorAPI().get_linstorapi()
        assert neterr.type == linstor.LinstorNetworkError


        # 重连linstor服务
        os.system('systemctl restart linstor-controller')
        time.sleep(5)
Beispiel #5
0
    def test_get_node(self):
        """
        环境
        ╭────────────────────────────────────────────────────────╮
        ┊ Node   ┊ NodeType ┊ Addresses                 ┊ State  ┊
        ╞════════════════════════════════════════════════════════╡
        ┊ ubuntu ┊ COMBINED ┊ 10.203.1.155:3366 (PLAIN) ┊ Online ┊
        ┊ vince2 ┊ COMBINED ┊ 10.203.1.157:3366 (PLAIN) ┊ Online ┊
        ╰────────────────────────────────────────────────────────╯
        """
        # 正常环境下,生成环境数据
        data1 = [{'Node': 'ubuntu', 'NodeType': 'COMBINED', 'Addresses': '10.203.1.155:3366 (PLAIN)', 'State': 'ONLINE'}, {'Node': 'vince2', 'NodeType': 'COMBINED', 'Addresses': '10.203.1.157:3366 (PLAIN)', 'State': 'ONLINE'}]
        data2 = [{'Node': 'ubuntu', 'NodeType': 'COMBINED', 'Addresses': '10.203.1.155:3366 (PLAIN)', 'State': 'ONLINE'}]
        # 获取全部node数据
        assert LinstorAPI().get_node() == data1

        # 获取指定node数据
        assert LinstorAPI().get_node(['ubuntu']) == data2
Beispiel #6
0
    def test_get_resource(self,):
        """
        环境
        ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
        ┊ Node   ┊ Resource ┊ StoragePool ┊ VolNr ┊ MinorNr ┊ DeviceName    ┊ Allocated ┊ InUse  ┊    State ┊
        ╞═══════════════════════════════════════════════════════════════════════════════════════════════════╡
        ┊ ubuntu ┊ res_a    ┊ pool_a      ┊     0 ┊    1000 ┊ /dev/drbd1000 ┊    12 MiB ┊ Unused ┊ UpToDate ┊
        ┊ vince2 ┊ res_b    ┊ pool_a      ┊     0 ┊    1010 ┊ /dev/drbd1010 ┊    12 MiB ┊ Unused ┊ UpToDate ┊
        ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
        """
        # 该环境下对应的数据
        data1 = [{'Node': 'ubuntu', 'Resource': 'res_a', 'StoragePool': 'pool_a', 'VolNr': '0', 'MinorNr': '1000', 'DeviceName': '/dev/drbd1000', 'Allocated': '12 MiB', 'InUse': 'Unused', 'State': 'UpToDate'}, {'Node': 'vince2', 'Resource': 'res_b', 'StoragePool': 'pool_a', 'VolNr': '0', 'MinorNr': '1010', 'DeviceName': '/dev/drbd1010', 'Allocated': '12 MiB', 'InUse': 'Unused', 'State': 'UpToDate'}]
        data2 = [{'Node': 'ubuntu', 'Resource': 'res_a', 'StoragePool': 'pool_a', 'VolNr': '0', 'MinorNr': '1000', 'DeviceName': '/dev/drbd1000', 'Allocated': '12 MiB', 'InUse': 'Unused', 'State': 'UpToDate'}]


        # 获取全部数据
        assert LinstorAPI().get_resource() == data1
        # 获取特定数据
        assert LinstorAPI().get_resource(['ubuntu'],['pool_a'],['res_a'])
Beispiel #7
0
    def test_get_volume_state(self):
        """
        环境:
        ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
        ┊ Node   ┊ Resource ┊ StoragePool ┊ VolNr ┊ MinorNr ┊ DeviceName    ┊ Allocated ┊ InUse  ┊    State ┊
        ╞═══════════════════════════════════════════════════════════════════════════════════════════════════╡
        ┊ ubuntu ┊ res_a    ┊ pool_a      ┊     0 ┊    1000 ┊ /dev/drbd1000 ┊    12 MiB ┊        ┊  Unknown ┊
        ┊ vince2 ┊ res_b    ┊ pool_a      ┊     0 ┊    1010 ┊ /dev/drbd1010 ┊    12 MiB ┊ Unused ┊ UpToDate ┊
        ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯

        """
        msg = LinstorAPI().get_linstorapi().volume_list(['ubuntu'],['pool_a'],['res_a'])[0]
        rsc_state_lkup = {x.node_name + x.name: x for x in msg.resource_states}
        for rsc in msg.resources:
            rsc_state = rsc_state_lkup.get(rsc.node_name + rsc.name)
            for vlm in rsc.volumes:
                # 正确的VolNr
                assert LinstorAPI().get_volume_state(rsc_state.volume_states,vlm.number)._rest_data is rsc_state.volume_states[0]._rest_data
                # 错误的VolNr
                assert LinstorAPI().get_volume_state(rsc_state.volume_states,1) is None
Beispiel #8
0
    def test_get_storagepool(self):
        """
        环境
        ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
        ┊ StoragePool          ┊ Node   ┊ Driver   ┊ PoolName ┊ FreeCapacity ┊ TotalCapacity ┊ CanSnapshots ┊ State ┊
        ╞═══════════════════════════════════════════════════════════════════════════════════════════════════════════╡
        ┊ DfltDisklessStorPool ┊ ubuntu ┊ DISKLESS ┊          ┊              ┊               ┊ False        ┊ Ok    ┊
        ┊ DfltDisklessStorPool ┊ vince2 ┊ DISKLESS ┊          ┊              ┊               ┊ False        ┊ Ok    ┊
        ┊ pool_a               ┊ ubuntu ┊ LVM      ┊          ┊    15.98 GiB ┊     16.00 GiB ┊ False        ┊ Ok    ┊
        ┊ pool_a               ┊ vince2 ┊ LVM      ┊          ┊    14.92 GiB ┊     16.00 GiB ┊ False        ┊ Ok    ┊
        ┊ pool_b               ┊ ubuntu ┊ LVM      ┊          ┊    15.98 GiB ┊     16.00 GiB ┊ False        ┊ Ok    ┊
        ┊ pool_sdc             ┊ ubuntu ┊ LVM      ┊          ┊    15.00 GiB ┊     15.00 GiB ┊ False        ┊ Ok    ┊
        ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯
        """

        # 该环境下对应的数据
        data1 = [{'StoragePool': 'DfltDisklessStorPool', 'Node': 'ubuntu', 'Driver': 'DISKLESS', 'PoolName': '', 'FreeCapacity': '', 'TotalCapacity': '', 'CanSnapshots': False, 'State': 'Ok'}, {'StoragePool': 'DfltDisklessStorPool', 'Node': 'vince2', 'Driver': 'DISKLESS', 'PoolName': '', 'FreeCapacity': '', 'TotalCapacity': '', 'CanSnapshots': False, 'State': 'Ok'}, {'StoragePool': 'pool_a', 'Node': 'ubuntu', 'Driver': 'LVM', 'PoolName': 'drbdpool', 'FreeCapacity': '15.98 GiB', 'TotalCapacity': '16.00 GiB', 'CanSnapshots': False, 'State': 'Ok'}, {'StoragePool': 'pool_a', 'Node': 'vince2', 'Driver': 'LVM', 'PoolName': 'drbdpool', 'FreeCapacity': '14.92 GiB', 'TotalCapacity': '16.00 GiB', 'CanSnapshots': False, 'State': 'Ok'}, {'StoragePool': 'pool_b', 'Node': 'ubuntu', 'Driver': 'LVM', 'PoolName': 'drbdpool', 'FreeCapacity': '15.98 GiB', 'TotalCapacity': '16.00 GiB', 'CanSnapshots': False, 'State': 'Ok'}, {'StoragePool': 'pool_sdc', 'Node': 'ubuntu', 'Driver': 'LVM', 'PoolName': 'vgsdc', 'FreeCapacity': '15.00 GiB', 'TotalCapacity': '15.00 GiB', 'CanSnapshots': False, 'State': 'Ok'}]
        data2 = [{'StoragePool': 'pool_a', 'Node': 'ubuntu', 'Driver': 'LVM', 'PoolName': 'drbdpool', 'FreeCapacity': '15.98 GiB', 'TotalCapacity': '16.00 GiB', 'CanSnapshots': False, 'State': 'Ok'}]
        # 获取全部数据
        assert LinstorAPI().get_storagepool() == data1

        # 获取特定数据
        assert LinstorAPI().get_storagepool(['ubuntu'],['pool_a']) == data2
Beispiel #9
0
class ClusterLVM(object):
    def __init__(self, node):
        try:
            self.api = LinstorAPI()
            self.sp = self.api.get_storagepool([node])
            self.res = self.api.get_resource([node])
        except AttributeError:
            self.sp = None
            self.res = None

        if node == utils.get_hostname():
            self.conn = None
        else:
            self.conn = utils.SSHConn(node)

        self.pv_list = self.get_pvs()
        self.vg_list = self.get_vgs()
        self.lv_list = self.get_lvs()

    # def create_linstor_thinpool(self, name, node, list_pv):
    #     pv = ' '.join(list_pv)
    #     cmd = f"linstor ps cdp --pool-name {name} lvmthin {node} {pv}"
    #     result = utils.exec_cmd(cmd, self.conn)
    #     if result["st"]:
    #         return True
    #     else:
    #         print(f"Failed to create Thinpool {name} via LINSTOR")
    #         return False

    # def create_linstor_vg(self, name, node, list_pv):
    #     pv = ' '.join(list_pv)
    #     cmd = f"linstor ps cdp --pool-name {name} lvm {node} {pv}"
    #     result = utils.exec_cmd(cmd, self.conn)
    #     if result["st"]:
    #         return True
    #     else:
    #         print(f"Failed to create VG {name} via LINSTOR")
    #         return False

    # def show_unused_device(self):
    #     """使用linstor命令展示可用的设备"""
    #     cmd = "linstor ps l"
    #     result = utils.exec_cmd(cmd, self.conn)
    #     if result["st"]:
    #         print(result["rt"])

    def get_lvm_device(self):
        """获取所有可见的LVM2设备"""
        cmd = "lvmdiskscan"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                lvm_list = re.findall('(\S+)\s+\[\s*(\S+\s\w+)\]\s+',
                                      result["rt"])
                return lvm_list

    def get_filesys(self):
        """获取所有可见的LVM2设备"""
        cmd = "df"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                fs_list = re.findall('(\S+)(?:\s+(?:\d+|-)){3}\s+\S+\s+\S\s*',
                                     result["rt"])
                return fs_list

    def get_pvs(self):
        """获取pv类型数据"""
        cmd = "pvs --noheadings"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                vgs_list = re.findall(
                    '(\S+)\s+(\S*)\s+lvm2\s+\S+\s+(\S+)\s+(\S+)\s*?',
                    result["rt"])
                # print(vgs_list)
                return vgs_list

    def get_vgs(self):
        """获取vg类型数据"""
        cmd = "vgs --noheadings"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                vgs_list = re.findall(
                    '(\S+)\s+(\d+)\s+(\d+)\s+\d+\s+\S+\s+(\S+)\s+(\S+)\s*?',
                    result["rt"])
                # print(vgs_list)
                return vgs_list

    def get_lvs(self):
        """获取lv类型数据"""
        cmd = "lvs --noheadings"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                vgs_list = re.findall(
                    '(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s(\S*).*\s', result["rt"])
                # pprint.pprint(vgs_list)
                return vgs_list

    def create_pv(self, device):
        """创建pv"""
        cmd = f"pvcreate {device} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in createing PV: {device}", 0)
            return True
        else:
            s.prt_log(f"Failed to create PV {device}", 1)
            return False

    def create_vg(self, name, list_pv):
        """创建vg"""
        pv = ' '.join(list_pv)
        cmd = f"vgcreate {name} {pv} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in createing VG: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to create VG {name}", 1)
            return False

    def create_lv(self, name, size, vg):
        """创建lv"""
        cmd = f"lvcreate -n {name} -L {size} {vg} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in createing LV: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to create LV: {name}", 1)
            return False

    def create_thinpool(self, name, size, vg):
        """创建thinpool"""
        cmd = f"lvcreate -T -L {size} {vg}/{name} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in createing Thinpool: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to create Thinpool {name}", 1)
            return False

    def create_thinpool_by_free_vg(self, name, vg):
        """使用当前VG的全部剩余空间创建thinpool"""
        create_cmd = f'lvcreate -l +100%free --thinpool {name} {vg} -y'
        utils.exec_cmd(create_cmd, self.conn)

    def create_thinlv(self, name, size, vg, thinpool):
        """创建thinlv"""
        cmd = f"lvcreate -V {size} -n {name} {vg}/{thinpool} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in createing Thin LV: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to create Thin LV {name}", 1)
            return False

    def del_pv(self, name):
        """删除PV"""
        cmd = f"pvremove {name} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in deleting PV: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to delete PV {name}", 1)
            return False

    def del_vg(self, name):
        """删除VG,删除前确认vg中是否还有lv"""
        self.vg_list = self.get_vgs()
        for vg in self.vg_list:
            if vg[0] == name:
                if int(vg[2]) > 0:
                    s.prt_log(
                        f"{name} still have other lv resource. Cancel delete {name}.",
                        2)
        cmd = f"vgremove {name} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in deleting VG: {name}", 0)
            return True
        else:
            s.prt_log(f"Failed to delete VG {name}", 1)
            return False

    def del_thinpool(self, vg, thinpool):
        """删除thinpool"""
        # lvremove /dev/linstor_vtel_pool/vtel_pool
        cmd = f"lvremove /dev/{vg}/{thinpool} -y"
        result = utils.exec_cmd(cmd, self.conn)
        if result["st"]:
            s.prt_log(f"Success in deleting Thinpool: {vg}/{thinpool}", 0)
            return True
        else:
            s.prt_log(f"Failed to delete Thinpool: {vg}/{thinpool}", 1)
            return False
        pass

    def check_thinpool(self, vg, thinpool):
        """
        检查Thinpool是不是被用作LINSTOR后端存储
        thinpool name: vg/poolname
        """
        if self.sp:
            for i in self.sp:
                if i['PoolName'] == f'{vg}/{thinpool}':
                    return i['StoragePool']

    def check_lv(self, lv):
        """检查lv是不是LINSTOR资源"""
        if self.res:
            for i in self.res:
                if f'{i["Resource"]}_00000' == lv:
                    return True

    def check_vg(self, vg):
        """检查vg是不是被用作LINSTOR后端存储"""
        if self.sp:
            for i in self.sp:
                if i["PoolName"] == vg:
                    return i["StoragePool"]

    def check_vg_exit(self, vg_name):
        if self.vg_list:
            for vg in self.vg_list:
                if vg[0] == vg_name:
                    return False
        return True

    def check_pv_exit(self, device_list):
        pv_in_use = []
        if self.pv_list:
            for pv in self.pv_list:
                if pv[0] in device_list:
                    pv_in_use.append(pv[0])
        if pv_in_use:
            pv_in_use_str = ",".join(pv_in_use)
            s.prt_log(f'{pv_in_use_str} have been used to create PV.', 1)
            return False
        else:
            return True

    def get_pv_via_vg(self, vg):
        """通过VG名获取对应的PV"""
        pv_dict = {}
        if self.pv_list:
            for pv in self.pv_list:
                if pv[1] == vg:
                    pv_dict[pv[0]] = pv[2]
        if not pv_dict:
            s.prt_log(f"{vg} is not vg resource", 2)
        return pv_dict

    def get_vg_via_thinpool(self, thinpool):
        """通过thinpool名获取对应的VG"""
        vg_list = []
        if self.lv_list:
            for lv in self.lv_list:
                if lv[0] == thinpool:
                    vg_list.append(lv[1])
        return vg_list

    def get_vg_free_pe(self, vg):
        """获取vg中剩余的PE个数"""
        cmd = f"vgdisplay {vg}"
        result = utils.exec_cmd(cmd, self.conn)
        if result:
            if result["st"]:
                re_free_pe = re.search(r'Free\s*PE / Size\s*(\d+)',
                                       result["rt"])
                re_used_flag = re.search(r'Alloc\s*PE / Size\s*(\d+)',
                                         result["rt"])
                free_pe = int(re_free_pe.group(1))
                if int(re_used_flag.group(1)) == 0:
                    free_pe = free_pe - 1
                return free_pe

    def get_device_size(self, device_list):
        size = 0
        lvm_list = self.get_lvm_device()
        for device in device_list:
            for lvm in lvm_list:
                if device == lvm[0]:
                    size = size + size_conversion(lvm[1]) - 4
        return size

    def check_and_get_size(self, data, size, type):
        """
        计算创建thinpool的可用空间大小,与用户输入的大小值进行比较
        data: vg_name or list device
        size: the size that user input
        type: vg or device
        """
        real_size = 0
        if type == "vg":
            real_size = real_size + int(self.get_vg_free_pe(data)) * 4 - (
                math.ceil((int(self.get_vg_free_pe(data)) * 4) / 4096) * 8)
        if type == "device":
            real_size = self.get_device_size(data)
            real_size = real_size - 4 - (math.ceil(real_size / 4096) * 8)
        available_size = real_size - 4
        if available_size <= 0:
            s.prt_log("No available space.", 2)
        if size:
            size = size_conversion(size)
            if size <= available_size:
                return size
            else:
                s.prt_log(
                    f"The size that you input is out of the actual available range (0,{available_size}M]",
                    2)
        else:
            return available_size

    def get_lvm_on_node(self):
        """将需要展示的数据处理成字典"""

        if not self.vg_list:
            s.prt_log("The node don't have VG.", 2)
        # pprint.pprint(self.res)
        # pprint.pprint(self.sp)

        vg_dict = {}
        for vg in self.vg_list:
            vg_data = {
                'total size': None,
                'free size': None,
                'linstor storage pool': {
                    'sp name': None
                }
            }
            pv_key = f'pvs({vg[1]})'
            lv_key = f'lvs({vg[2]})'
            vg_data['total size'] = vg[3]
            vg_data['free size'] = vg[4]
            vg_data[pv_key] = None
            vg_data[lv_key] = None
            lv_dict = {}
            pv_dict = self.get_pv_via_vg(vg[0])
            vg_data[pv_key] = pv_dict if pv_dict else None

            if self.lv_list:
                for lv in self.lv_list:
                    if lv[1] == vg[0]:
                        # lv
                        if '-wi-' in lv[2]:
                            status = True if self.check_lv(lv[0]) else False
                            lv_dict[lv[0]] = {
                                "size": lv[3],
                                'linstor resource': status
                            }
                        # thinpool
                        elif 'twi-' in lv[2]:
                            sp_ = self.check_thinpool(lv[1], lv[0])
                            lv_dict[lv[0]] = {
                                "size": lv[3],
                                'linstor storage pool': {
                                    'sp name': sp_
                                }
                            }
                        # elif 'Vwi-' in lv[2]:
                        #     lv_dict[lv[0]] = {"size": lv[3], 'linstor resource': False}
            vg_data[lv_key] = lv_dict if lv_dict else None

            for pool in lv_dict:
                pool_dict = {}
                # thinlv
                if self.lv_list:
                    for lv in self.lv_list:
                        if lv[4] == pool and lv[1] == vg[0]:
                            thinlv_status = True if self.check_lv(
                                lv[0]) else False
                            pool_dict[lv[0]] = {
                                "size": lv[3],
                                'linstor resource': thinlv_status
                            }
                if len(pool_dict) != 0:
                    pool_key = f'lvs({len(pool_dict)})'
                    vg_data[lv_key][pool][
                        pool_key] = pool_dict if pool_dict else None

            vg_dict[vg[0]] = vg_data

            vg_status = self.check_vg(vg[0])
            vg_data["linstor storage pool"]["sp name"] = vg_status

        return vg_dict

    def show_vg(self, vg=None):
        """以YAML格式展示JSON数据"""
        dict_vg = self.get_lvm_on_node()
        if not self.res and not self.sp:
            print('-' * 10, "Can't get LINSTOR resource", '-' * 10)
        try:
            if vg:
                print('-' * 15, vg, '-' * 15)
                s.prt_log(yaml.dump(dict_vg[vg], sort_keys=False), 0)
            else:
                s.prt_log(yaml.dump(dict_vg, sort_keys=False), 0)
        except KeyError:
            s.prt_log(f"{vg} does not exit.", 1)

    def show_unused_lvm_device(self):
        """表格展示未被用来创建PV的LVM设备"""
        print('-' * 15, "Unused Device", '-' * 15)
        list_header = ["Device", "Size"]
        lvm_list = self.get_lvm_device()
        fs_list = self.get_filesys()
        if lvm_list:
            unused_lvm_device = list(lvm_list)
            if self.pv_list:
                for pv in self.pv_list:
                    for device in lvm_list:
                        if pv[0] == device[0]:
                            unused_lvm_device.remove(device)
            unused_lvm_device_without_fs = [
                i for i in unused_lvm_device if i[0] not in fs_list
                and "/dev/drbd" not in i[0] and "_00000" not in i[0]
            ]
            s.prt_log(s.make_table(list_header, unused_lvm_device_without_fs),
                      0)
        else:
            s.prt_log(f"No message of unused device", 1)

    def delete_vg(self, vg):
        if not self.check_vg(vg):
            pv_dict = self.get_pv_via_vg(vg)
            if self.del_vg(vg):
                for pv in pv_dict.keys():
                    self.del_pv(pv)
        else:
            s.prt_log(f"{vg} is in used", 1)

    def delete_thinpool(self, thinpool, confirm):
        vg_list = self.get_vg_via_thinpool(thinpool)
        if not vg_list:
            s.prt_log(f"{thinpool} is not thinpool resource", 2)
        if len(vg_list) > 1:
            print(
                f'Thinpool with the same name "{thinpool}" exist in those vg: {vg_list}'
            )
            vg = input(
                "Input the VG Name that the thinpool you want to delete:")
            if vg.strip() in vg_list:
                vg = vg.strip()
            else:
                s.prt_log("Error VG Name", 2)
        else:
            vg = vg_list[0]
        if not self.check_thinpool(vg, thinpool):
            if self.del_thinpool(vg, thinpool):
                pv_dict = self.get_pv_via_vg(vg)
                if confirm:
                    if self.del_vg(vg):
                        for pv in pv_dict.keys():
                            self.del_pv(pv)
        else:
            s.prt_log(f"{thinpool} is in used", 1)