def access_group_init_add(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. Already in requested access group, return silently. # 2. Initiator does not exist. # 3. Initiator not used by other access group. if init_id in list(NodeACLGroup(tpg, ag_name).wwns): return for node_acl_group in tpg.node_acl_groups: if init_id in list(node_acl_group.wwns): raise TargetdError( TargetdError.EXISTS_INITIATOR, "Requested init_id is used by other access group") for node_acl in tpg.node_acls: if init_id == node_acl.node_wwn: raise TargetdError(TargetdError.EXISTS_INITIATOR, "Requested init_id is in use") NodeACLGroup(tpg, ag_name).add_acl(init_id) RTSRoot().save_to_file()
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(-110, "Invalid pool")
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') NetworkPortal(tpg, "0.0.0.0") 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 LUN.MAX_LUN free_h_lun_ids = set(range(LUN.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" % LUN.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()
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()
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 = "%s:%s" % (pool, name) if so_name in (lun.storage_object.name for lun in tpg.luns): raise TargetdError( -303, "Volume '%s' cannot be " "removed while exported" % name) with vgopen(get_vg_lv(pool)[0]) as vg: vg.lvFromName(name).remove()
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()
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))
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) with vgopen(vg_name) as vg: if not thin_pool: raise RuntimeError("copy requires thin-provisioned volumes") try: vg.lvFromName(vol_orig).snapshot(vol_new) except AttributeError: raise NotImplementedError("liblvm lacks thin snap support")
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, )
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()