示例#1
0
def pool_check(pool_name):
    """
        pool_name *cannot* be trusted, funcs taking a pool param must call
        this or vgopen() to ensure passed-in pool name is one targetd has
        been configured to use.
    """
    if not has_pool(pool_name):
        raise TargetdError(TargetdError.INVALID_POOL, "Invalid pool (LVM)")
示例#2
0
def create(req, pool, name, size):
    mod = pool_module(pool)
    # Check to ensure that we don't have a volume with this name already,
    # lvm/zfs will fail if we try to create a LV/dataset with a duplicate name
    if check_vol_exists(req, pool, name):
        raise TargetdError(TargetdError.NAME_CONFLICT,
                           "Volume with that name exists")
    mod.create(req, pool, name, size)
示例#3
0
文件: zfs.py 项目: whywaita/targetd
def fs_snapshot(req, pool, name, dest_ss_name):
    _check_dataset_name(name)
    _check_dataset_name(dest_ss_name)

    zfs_pool = pools_fs[pool]

    info = snap_info(zfs_pool, name, dest_ss_name)
    if info is not None:
        raise TargetdError(
            TargetdError.EXISTS_FS_NAME,
            "Snapshot {0} already exists on pool {1} for {2}".format(
                dest_ss_name, pool, name))

    code, out, err = _zfs_exec_command(
        ["snapshot", "{0}/{1}@{2}".format(zfs_pool, name, dest_ss_name)])
    if code != 0:
        raise TargetdError(TargetdError.UNEXPECTED_EXIT_CODE,
                           "Could not create snapshot")
示例#4
0
def _zfs_find_cmd():
    cmd = distutils.spawn.find_executable('zfs') \
          or distutils.spawn.find_executable('zfs', '/sbin:/usr/sbin')
    if cmd is None or not cmd:
        raise TargetdError(
            TargetdError.INVALID,
            "zfs_block_pools is set but no zfs command was found")
    global zfs_cmd
    zfs_cmd = cmd
示例#5
0
def destroy(req, pool, name):
    mod = pool_module(pool)
    if not check_vol_exists(req, pool, name):
        raise TargetdError(TargetdError.NOT_FOUND_VOLUME,
                           "Volume %s not found in pool %s" % (name, pool))

    with ignored(RTSLibNotInCFS):
        fm = FabricModule('iscsi')
        t = Target(fm, target_name, mode='lookup')
        tpg = TPG(t, 1, mode='lookup')

        so_name = get_so_name(pool, name)

        if so_name in (lun.storage_object.name for lun in tpg.luns):
            raise TargetdError(TargetdError.VOLUME_MASKED,
                               "Volume '%s' cannot be "
                               "removed while exported" % name)

    pool_module(pool).destroy(req, pool, name)
示例#6
0
def pool_check(pool_name):
    """
    pool_name *cannot* be trusted, funcs taking a pool param must call
    this or vgopen() to ensure passed-in pool name is one targetd has
    been configured to use.
    """
    pool_to_check = get_vg_lv(pool_name)[0]

    if pool_to_check not in [get_vg_lv(x)[0] for x in pools]:
        raise TargetdError(TargetdError.INVALID_POOL, "Invalid pool")
示例#7
0
def copy(req, pool, vol_orig, vol_new, timeout=10):
    """
    Create a new volume that is a copy of an existing one.
    Since 0.6, requires thinp support.
    """
    if any(v['name'] == vol_new for v in volumes(req, pool)):
        raise TargetdError(TargetdError.NAME_CONFLICT,
                           "Volume with that name exists")

    vg_name, thin_pool = get_vg_lv(pool)

    if not thin_pool:
        raise RuntimeError("copy requires thin-provisioned volumes")

    try:
        bd.lvm.thsnapshotcreate(vg_name, vol_orig, vol_new, thin_pool)
    except bd.LVMError as err:
        raise TargetdError(TargetdError.UNEXPECTED_EXIT_CODE,
                           "Failed to copy volume, "
                           "nested error: {}".format(str(err).strip()))
示例#8
0
文件: zfs.py 项目: whywaita/targetd
def destroy(req, pool, name):
    _check_dataset_name(name)
    # -r will destroy snapshots and children but not dependant clones
    code, out, err = _zfs_exec_command(["destroy", "-r", pool + "/" + name])
    if code != 0:
        if b'volume has dependent clones' in err:
            logging.error(
                "Volume %s on %s has dependent clones and cannot be destroyed. Stderr: %s"
                % (name, pool, err))
            raise TargetdError(
                TargetdError.INVALID_ARGUMENT,
                "Volume %s on %s has dependent clones and cannot be destroyed."
                % (name, pool))
        else:
            logging.error(
                "Could not destroy volume %s on pool %s. Code: %s, stderr %s" %
                (name, pool, code, err))
        raise TargetdError(
            TargetdError.UNEXPECTED_EXIT_CODE,
            "Could not destroy volume %s on pool %s" % (name, pool))
示例#9
0
文件: zfs.py 项目: whywaita/targetd
def create(req, pool, name, size):
    _check_dataset_name(name)
    code, out, err = _zfs_exec_command(
        ["create", "-V", str(size), pool + "/" + name])
    if code != 0:
        logging.error(
            "Could not create volume %s on pool %s. Code: %s, stderr %s" %
            (name, pool, code, err))
        raise TargetdError(
            TargetdError.UNEXPECTED_EXIT_CODE,
            "Could not create volume %s on pool %s" % (name, pool))
示例#10
0
def access_group_map_create(req, pool_name, vol_name, ag_name, h_lun_id=None):
    tpg = _get_iscsi_tpg()
    tpg.enable = True
    tpg.set_attribute("authentication", '0')

    set_portal_addresses(tpg)

    tpg_lun = _tpg_lun_of(tpg, pool_name, vol_name)

    # Pre-Check:
    #   1. Already mapped to requested access group, return None
    if any(tpg_lun.mapped_luns):
        tgt_map_list = access_group_map_list(req)
        for tgt_map in tgt_map_list:
            if tgt_map['ag_name'] == ag_name and \
                    tgt_map['pool_name'] == pool_name and \
                    tgt_map['vol_name'] == vol_name:
                # Already masked.
                return None

    node_acl_group = NodeACLGroup(tpg, ag_name)
    if not any(node_acl_group.wwns):
        # Non-existent access group means volume mapping status will not be
        # stored. This should be considered as an error instead of silently
        # returning.
        raise TargetdError(TargetdError.NOT_FOUND_ACCESS_GROUP,
                           "Access group not found")

    if h_lun_id is None:
        # Find out next available host LUN ID
        # Assuming max host LUN ID is MAX_LUN
        free_h_lun_ids = set(range(MAX_LUN + 1)) - \
                         set([int(x.mapped_lun) for x in tpg_lun.mapped_luns])
        if len(free_h_lun_ids) == 0:
            raise TargetdError(TargetdError.NO_FREE_HOST_LUN_ID,
                               "All host LUN ID 0 ~ %d is in use" % MAX_LUN)
        else:
            h_lun_id = free_h_lun_ids.pop()

    node_acl_group.mapped_lun_group(h_lun_id, tpg_lun)
    RTSRoot().save_to_file()
示例#11
0
def access_group_init_del(req, ag_name, init_id, init_type):
    if init_type != 'iscsi':
        raise TargetdError(TargetdError.NO_SUPPORT, "Only support iscsi")

    tpg = _get_iscsi_tpg()

    # Pre-check:
    #   1. Initiator is not in requested access group, return silently.
    if init_id not in list(NodeACLGroup(tpg, ag_name).wwns):
        return

    NodeACLGroup(tpg, ag_name).remove_acl(init_id)
    RTSRoot().save_to_file()
示例#12
0
def check_pools_access(check_pools):
    for pool in check_pools:
        thinp = None
        error = ""
        vg_name, thin_pool = get_vg_lv(pool)

        if vg_name and thin_pool:
            # We have VG name and LV name, check for it!
            try:
                thinp = bd.lvm.lvinfo(vg_name, thin_pool)
            except bd.LVMError as lve:
                error = str(lve).strip()

            if thinp is None:
                raise TargetdError(
                    TargetdError.NOT_FOUND_VOLUME_GROUP,
                    "VG with thin LV {} not found, "
                    "nested error: {}".format(pool, error))
        else:
            try:
                bd.lvm.vginfo(vg_name)
            except bd.LVMError as vge:
                error = str(vge).strip()
                raise TargetdError(
                    TargetdError.NOT_FOUND_VOLUME_GROUP,
                    "VG pool {} not found, "
                    "nested error: {}".format(vg_name, error))

        # Allowed multi-pool configs:
        # two thinpools from a single vg: ok
        # two vgs: ok
        # vg and a thinpool from that vg: BAD
        #
        if thin_pool and vg_name in check_pools:
            raise TargetdError(
                TargetdError.INVALID,
                "VG pool and thin pool from same VG not supported")

    return
示例#13
0
文件: block.py 项目: triluch/targetd
def destroy(req, pool, name):
    with ignored(RTSLibNotInCFS):
        fm = FabricModule('iscsi')
        t = Target(fm, target_name, mode='lookup')
        tpg = TPG(t, 1, mode='lookup')

        so_name = get_so_name(pool, name)

        if so_name in (lun.storage_object.name for lun in tpg.luns):
            raise TargetdError(
                TargetdError.VOLUME_MASKED, "Volume '%s' cannot be "
                "removed while exported" % name)

    pool_module(pool).destroy(req, pool, name)
示例#14
0
def fs_snapshot_delete(req, pool, name, ss_name):
    _check_dataset_name(name)
    _check_dataset_name(ss_name)

    zfs_pool = pools_fs[pool]

    info = snap_info(zfs_pool, name, ss_name)
    if info is None:
        return

    code, out, err = _zfs_exec_command(["destroy", "-r", "{0}/{1}@{2}".format(zfs_pool, name, ss_name)])
    if code != 0:
        raise TargetdError(TargetdError.UNEXPECTED_EXIT_CODE,
                           "Could not destroy snapshot")
示例#15
0
def access_group_create(req, ag_name, init_id, init_type):
    if init_type != 'iscsi':
        raise TargetdError(TargetdError.NO_SUPPORT, "Only support iscsi")

    name_check(ag_name)

    tpg = _get_iscsi_tpg()

    # Pre-check:
    #   1. Name conflict: requested name is in use
    #   2. Initiator conflict:  request initiator is in use

    for node_acl_group in tpg.node_acl_groups:
        if node_acl_group.name == ag_name:
            raise TargetdError(TargetdError.NAME_CONFLICT,
                               "Requested access group name is in use")

    if init_id in list(i.node_wwn for i in tpg.node_acls):
        raise TargetdError(TargetdError.EXISTS_INITIATOR,
                           "Requested init_id is in use")

    node_acl_group = NodeACLGroup(tpg, ag_name)
    node_acl_group.add_acl(init_id)
    RTSRoot().save_to_file()
示例#16
0
def destroy(req, pool, name):
    with ignored(RTSLibNotInCFS):
        fm = FabricModule('iscsi')
        t = Target(fm, target_name, mode='lookup')
        tpg = TPG(t, 1, mode='lookup')

        vg_name, lv_pool = get_vg_lv(pool)
        so_name = "%s:%s" % (vg_name, name)

        if so_name in (lun.storage_object.name for lun in tpg.luns):
            raise TargetdError(
                TargetdError.VOLUME_MASKED, "Volume '%s' cannot be "
                "removed while exported" % name)

    with vgopen(get_vg_lv(pool)[0]) as vg:
        vg.lvFromName(name).remove()
示例#17
0
def create(req, pool, name, size):
    # Check to ensure that we don't have a volume with this name already,
    # lvm will fail if we try to create a LV with a duplicate name
    if any(v['name'] == name for v in volumes(req, pool)):
        raise TargetdError(TargetdError.NAME_CONFLICT,
                           "Volume with that name exists")

    vg_name, lv_pool = get_vg_lv(pool)
    if lv_pool:
        # Fall back to non-thinp if needed
        try:
            bd.lvm.thlvcreate(vg_name, lv_pool, name, int(size))
        except bd.LVMError:
            bd.lvm.lvcreate(vg_name, name, int(size), 'linear')
    else:
        bd.lvm.lvcreate(vg_name, name, int(size), 'linear')
示例#18
0
def copy(req, pool, vol_orig, vol_new, timeout=10):
    """
    Create a new volume that is a copy of an existing one.
    Since 0.6, requires thinp support.
    """
    if any(v['name'] == vol_new for v in volumes(req, pool)):
        raise TargetdError(TargetdError.NAME_CONFLICT,
                           "Volume with that name exists")

    vg_name, thin_pool = get_vg_lv(pool)

    if not thin_pool:
        raise RuntimeError("copy requires thin-provisioned volumes")

    try:
        bd.lvm.thsnapshotcreate(vg_name, vol_orig, vol_new, thin_pool)
    except AttributeError:
        raise NotImplementedError("liblvm lacks thin snap support")
示例#19
0
def create(req, pool, name, size):

    # Check to ensure that we don't have a volume with this name already,
    # lvm will fail if we try to create a LV with a duplicate name
    if any(v['name'] == name for v in volumes(req, pool)):
        raise TargetdError(TargetdError.NAME_CONFLICT,
                           "Volume with that name exists")

    vg_name, lv_pool = get_vg_lv(pool)
    with vgopen(vg_name) as vg:
        if lv_pool:
            # Fall back to non-thinp if needed
            try:
                vg.createLvThin(lv_pool, name, int(size))
            except AttributeError:
                vg.createLvLinear(name, int(size))
        else:
            vg.createLvLinear(name, int(size))
示例#20
0
def initialize(config_dict):

    global pools
    pools = config_dict['block_pools']

    global target_name
    target_name = config_dict['target_name']

    # fail early if can't access any vg
    for pool in pools:
        vg_name, thin_pool = get_vg_lv(pool)
        test_vg = lvm.vgOpen(vg_name)
        test_vg.close()

        # Allowed multi-pool configs:
        # two thinpools from a single vg: ok
        # two vgs: ok
        # vg and a thinpool from that vg: BAD
        #
        if thin_pool and vg_name in pools:
            raise TargetdError(
                -1, "VG pool and thin pool from same VG not supported")

    return dict(
        vol_list=volumes,
        vol_create=create,
        vol_destroy=destroy,
        vol_copy=copy,
        export_list=export_list,
        export_create=export_create,
        export_destroy=export_destroy,
        initiator_set_auth=initiator_set_auth,
        initiator_list=initiator_list,
        access_group_list=access_group_list,
        access_group_create=access_group_create,
        access_group_destroy=access_group_destroy,
        access_group_init_add=access_group_init_add,
        access_group_init_del=access_group_init_del,
        access_group_map_list=access_group_map_list,
        access_group_map_create=access_group_map_create,
        access_group_map_destroy=access_group_map_destroy,
    )
示例#21
0
文件: block.py 项目: triluch/targetd
def initialize(config_dict):
    global pools
    pools["lvm"] = list(config_dict['block_pools'])
    pools["zfs"] = list(config_dict['zfs_block_pools'])

    global target_name
    target_name = config_dict['target_name']

    global addresses
    addresses = config_dict['portal_addresses']

    if any(i in pools['zfs'] for i in pools['lvm']):
        raise TargetdError(
            TargetdError.INVALID,
            "Conflicting names in zfs_block_pools and block_pools in config.")

    # initialize and check both pools
    for modname, mod in pool_modules.items():
        mod.initialize(pools[modname])

    return dict(
        vol_list=volumes,
        vol_create=create,
        vol_destroy=destroy,
        vol_copy=copy,
        export_list=export_list,
        export_create=export_create,
        export_destroy=export_destroy,
        initiator_set_auth=initiator_set_auth,
        initiator_list=initiator_list,
        access_group_list=access_group_list,
        access_group_create=access_group_create,
        access_group_destroy=access_group_destroy,
        access_group_init_add=access_group_init_add,
        access_group_init_del=access_group_init_del,
        access_group_map_list=access_group_map_list,
        access_group_map_create=access_group_map_create,
        access_group_map_destroy=access_group_map_destroy,
    )
示例#22
0
def export_destroy(req, pool, vol, initiator_wwn):
    mod = pool_module(pool)
    fm = FabricModule('iscsi')
    t = Target(fm, target_name)
    tpg = TPG(t, 1)
    na = NodeACL(tpg, initiator_wwn)

    pool_dev_name = mod.pool2dev_name(pool)

    for mlun in na.mapped_luns:
        # all SOs are Block so we can access udev_path safely
        if mod.has_udev_path(mlun.tpg_lun.storage_object.udev_path):
            mlun_vg, mlun_name = \
                mod.split_udev_path(mlun.tpg_lun.storage_object.udev_path)

            if mlun_vg == pool_dev_name and mlun_name == vol:
                tpg_lun = mlun.tpg_lun
                mlun.delete()
                # be tidy and delete unused tpg lun mappings?
                if not any(tpg_lun.mapped_luns):
                    so = tpg_lun.storage_object
                    tpg_lun.delete()
                    so.delete()
                break
    else:
        raise TargetdError(TargetdError.NOT_FOUND_VOLUME_EXPORT,
                           "Volume '%s' not found in %s exports" %
                           (vol, initiator_wwn))

    # Clean up tree if branch has no leaf
    if not any(na.mapped_luns):
        na.delete()
        if not any(tpg.node_acls):
            tpg.delete()
            if not any(t.tpgs):
                t.delete()

    RTSRoot().save_to_file()
示例#23
0
def export_destroy(req, pool, vol, initiator_wwn):
    pool_check(pool)
    fm = FabricModule('iscsi')
    t = Target(fm, target_name)
    tpg = TPG(t, 1)
    na = NodeACL(tpg, initiator_wwn)

    vg_name, thin_pool = get_vg_lv(pool)

    for mlun in na.mapped_luns:
        # all SOs are Block so we can access udev_path safely
        mlun_vg, mlun_name = \
            mlun.tpg_lun.storage_object.udev_path.split("/")[2:]

        if mlun_vg == vg_name and mlun_name == vol:
            tpg_lun = mlun.tpg_lun
            mlun.delete()
            # be tidy and delete unused tpg lun mappings?
            if not any(tpg_lun.mapped_luns):
                so = tpg_lun.storage_object
                tpg_lun.delete()
                so.delete()
            break
    else:
        raise TargetdError(
            -151, "Volume '%s' not found in %s exports" % (vol, initiator_wwn))

    # Clean up tree if branch has no leaf
    if not any(na.mapped_luns):
        na.delete()
        if not any(tpg.node_acls):
            tpg.delete()
            if not any(t.tpgs):
                t.delete()

    RTSRoot().save_to_file()
示例#24
0
def copy(req, pool, vol_orig, vol_new, timeout=10):
    mod = pool_module(pool)
    if not check_vol_exists(req, pool, vol_orig):
        raise TargetdError(TargetdError.NOT_FOUND_VOLUME,
                           "Volume %s not found in pool %s" % (vol_orig, pool))
    pool_module(pool).copy(req, pool, vol_orig, vol_new, timeout)
示例#25
0
文件: block.py 项目: yuanying/targetd
def initialize(config_dict):

    global pools
    pools = config_dict['block_pools']

    global target_name
    target_name = config_dict['target_name']

    global addresses
    addresses = config_dict['portal_addresses']

    # fail early if can't access any vg
    for pool in pools:
        thinp = None
        error = ""
        vg_name, thin_pool = get_vg_lv(pool)

        if vg_name and thin_pool:
            # We have VG name and LV name, check for it!
            try:
                thinp = bd.lvm.lvinfo(vg_name, thin_pool)
            except bd.LVMError as lve:
                error = str(lve).strip()

            if thinp is None:
                raise TargetdError(
                    TargetdError.NOT_FOUND_VOLUME_GROUP,
                    "VG with thin LV {} not found, "
                    "nested error: {}".format(pool, error))
        else:
            try:
                bd.lvm.vginfo(vg_name)
            except bd.LVMError as vge:
                error = str(vge).strip()
                raise TargetdError(
                    TargetdError.NOT_FOUND_VOLUME_GROUP,
                    "VG pool {} not found, "
                    "nested error: {}".format(vg_name, error))

        # Allowed multi-pool configs:
        # two thinpools from a single vg: ok
        # two vgs: ok
        # vg and a thinpool from that vg: BAD
        #
        if thin_pool and vg_name in pools:
            raise TargetdError(
                TargetdError.INVALID,
                "VG pool and thin pool from same VG not supported")

    return dict(
        vol_list=volumes,
        vol_create=create,
        vol_destroy=destroy,
        vol_copy=copy,
        export_list=export_list,
        export_create=export_create,
        export_destroy=export_destroy,
        initiator_set_auth=initiator_set_auth,
        initiator_list=initiator_list,
        access_group_list=access_group_list,
        access_group_create=access_group_create,
        access_group_destroy=access_group_destroy,
        access_group_init_add=access_group_init_add,
        access_group_init_del=access_group_init_del,
        access_group_map_list=access_group_map_list,
        access_group_map_create=access_group_map_create,
        access_group_map_destroy=access_group_map_destroy,
    )
示例#26
0
文件: zfs.py 项目: whywaita/targetd
def _check_dataset_name(name):
    if not ALLOWED_DATASET_NAMES.match(name):
        raise TargetdError(
            TargetdError.INVALID_ARGUMENT,
            "Invalid dataset name, can only contain alphanumeric characters,"
            "underscores, dots and hyphens")
示例#27
0
def copy(req, pool, vol_orig, vol_new, timeout=10):
    # TODO: should be easy to do with snapshots
    raise TargetdError(TargetdError.NO_SUPPORT, "Copy not yet impletmented on ZFS pools")
示例#28
0
def so_name_module(so_name):
    for modname, mod in pool_modules.items():
        if mod.has_so_name(so_name):
            return mod
    raise TargetdError(TargetdError.INVALID_POOL,
                       "Pool not found by storage object (%s)" % so_name)
示例#29
0
def udev_path_module(udev_path):
    for modname, mod in pool_modules.items():
        if mod.has_udev_path(udev_path):
            return mod
    raise TargetdError(TargetdError.INVALID_POOL,
                       "Pool not found by udev path (%s)" % udev_path)
示例#30
0
def pool_module(pool_name):
    for modname, mod in pool_modules.items():
        if mod.has_pool(pool_name):
            return mod
    raise TargetdError(TargetdError.INVALID_POOL,
                       "Invalid pool (%s)" % pool_name)