def _get_portals(self, tpg): """ return a list of network portal IPs allocated to a specfic tpg :param tpg: tpg to check (object) :return: list of IP's this tpg has (list) """ return [normalize_ip_address(portal.ip_address) for portal in tpg.network_portals]
def ui_command_create(self, gateway_name, ip_address, nosync=False, skipchecks='false'): """ Define a gateway to the gateway group for this iscsi target. The first host added should be the gateway running the command gateway_name ... should resolve to the hostname of the gateway ip_address ..... is the IPv4/IPv6 address of the interface the iscsi portal should use nosync ......... by default new gateways are sync'd with the existing configuration by cli. By specifying nosync the sync step is bypassed - so the new gateway will need to have it's rbd-target-gw daemon restarted to apply the current configuration (default = False) skipchecks ..... set this to true to force gateway validity checks to be bypassed(default = False). This is a developer option ONLY. Skipping these checks has the potential to result in an unstable configuration. """ ip_address = normalize_ip_address(ip_address) self.logger.debug("CMD: ../gateways/ create {} {} " "nosync={} skipchecks={}".format(gateway_name, ip_address, nosync, skipchecks)) local_gw = this_host() current_gateways = [tgt.name for tgt in self.children] if gateway_name != local_gw and len(current_gateways) == 0: # the first gateway defined must be the local machine. By doing # this the initial create uses localhost, and places it's portal IP # in the gateway ip list. Once the gateway ip list is defined, the # api server can resolve against the gateways - until the list is # defined only a request from localhost is acceptable to the api self.logger.error("The first gateway defined must be the local " "machine") return if skipchecks not in ['true', 'false']: self.logger.error("skipchecks must be either true or false") return if local_gw in current_gateways: current_gateways.remove(local_gw) config = self.parent.parent.parent._get_config() if not config: self.logger.error("Unable to refresh local config" " over API - sync aborted, restart rbd-target-gw" " on {} to sync".format(gateway_name)) target_iqn = self.parent.name target_config = config['targets'][target_iqn] if nosync: sync_text = "sync skipped" else: sync_text = ("sync'ing {} disk(s) and " "{} client(s)".format(len(target_config['disks']), len(target_config['clients']))) if skipchecks == 'true': self.logger.warning("OS version/package checks have been bypassed") self.logger.info("Adding gateway, {}".format(sync_text)) gw_api = '{}://{}:{}/api'.format(self.http_mode, "localhost", settings.config.api_port) gw_rqst = gw_api + '/gateway/{}/{}'.format(target_iqn, gateway_name) gw_vars = {"nosync": nosync, "skipchecks": skipchecks, "ip_address": ip_address} api = APIRequest(gw_rqst, data=gw_vars) api.put() msg = response_message(api.response, self.logger) if api.response.status_code != 200: self.logger.error("Failed : {}".format(msg)) return self.logger.debug("{}".format(msg)) self.logger.debug("Adding gw to UI") # Target created OK, get the details back from the gateway and # add to the UI. We have to use the new gateway to ensure what # we get back is current (the other gateways will lag until they see # epoch xattr change on the config object) new_gw_endpoint = ('{}://{}:{}/' 'api'.format(self.http_mode, gateway_name, settings.config.api_port)) config = self.parent.parent.parent._get_config(endpoint=new_gw_endpoint) target_config = config['targets'][target_iqn] portal_config = target_config['portals'][gateway_name] Gateway(self, gateway_name, portal_config) self.logger.info('ok')
def __init__(self, logger, iqn, gateway_ip_list, enable_portal=True): """ Instantiate the class :param iqn: iscsi iqn name for the gateway :param gateway_ip_list: list of IP addresses to be defined as portals to LIO :return: gateway object """ self.error = False self.error_msg = '' self.enable_portal = enable_portal # boolean to trigger portal IP creation self.logger = logger # logger object try: iqn, iqn_type = normalize_wwn(['iqn'], iqn) except RTSLibError as err: self.error = True self.error_msg = "Invalid iSCSI target name - {}".format(err) self.iqn = iqn # Ensure IPv6 addresses are in the normalized address (not literal) format gateway_ip_list = [normalize_ip_address(x) for x in gateway_ip_list] # If the ip list received has data in it, this is a target we need to # act on the IP's provided, otherwise just set to null if gateway_ip_list: # if the ip list provided doesn't match any ip of this host, abort # the assumption here is that we'll only have one matching ip in # the list! matching_ip = set(gateway_ip_list).intersection(ip_addresses()) if len(list(matching_ip)) == 0: self.error = True self.error_msg = ("gateway IP addresses provided do not match" " any ip on this host") return self.active_portal_ip = list(matching_ip)[0] self.logger.debug("active portal will use " "{}".format(self.active_portal_ip)) self.gateway_ip_list = gateway_ip_list self.logger.debug("tpg's will be defined in this order" " - {}".format(self.gateway_ip_list)) else: # without gateway_ip_list passed in this is a 'init' or # 'clearconfig' request self.gateway_ip_list = [] self.active_portal_ip = [] self.changes_made = False self.config_updated = False # self.portal = None self.target = None self.tpg = None self.tpg_list = [] try: super(GWTarget, self).__init__('targets', iqn, logger, GWTarget.SETTINGS) except CephiSCSIError as err: self.error = True self.error_msg = err
def bind_alua_group_to_lun(self, config, lun, tpg_ip_address=None): """ bind lun to one of the alua groups. Query the config to see who 'owns' the primary path for this LUN. Then either bind the LUN to the ALUA 'AO' group if the host matches, or default to the 'ANO'/'Standby' alua group param config: Config object param lun: lun object on the tpg param tpg_ip: IP of Network Portal for the lun's tpg. """ stg_object = lun.storage_object owning_gw = config.config['disks'][stg_object.name]['owner'] tpg = lun.parent_tpg if not tpg_ip_address: # just need to check one portal for ip in tpg.network_portals: tpg_ip_address = normalize_ip_address(ip.ip_address) break if tpg_ip_address is None: # this is being run during boot so the NP is not setup yet. return target_config = config.config["targets"][self.iqn] is_owner = False if target_config['portals'][owning_gw][ "portal_ip_address"] == tpg_ip_address: is_owner = True try: alua_tpg = alua_create_group(settings.config.alua_failover_type, tpg, stg_object, is_owner) except CephiSCSIInval: raise except RTSLibError: self.logger.info("ALUA group id {} for stg obj {} lun {} " "already made".format(tpg.tag, stg_object, lun)) group_name = alua_format_group_name( tpg, settings.config.alua_failover_type, is_owner) # someone mapped a LU then unmapped it without deleting the # stg_object, or we are reloading the config. alua_tpg = ALUATargetPortGroup(stg_object, group_name) if alua_tpg.tg_pt_gp_id != tpg.tag: # ports and owner were rearranged. Not sure we support that. raise CephiSCSIInval("Existing ALUA group tag for group {} " "in invalid state.\n".format(group_name)) # drop down in case we are restarting due to error and we # were not able to bind to a lun last time. self.logger.info( "Setup group {} for {} on tpg {} (state {}, owner {}, " "failover type {})".format(alua_tpg.name, stg_object.name, tpg.tag, alua_tpg.alua_access_state, is_owner, alua_tpg.alua_access_type)) self.logger.debug("Setting Luns tg_pt_gp to {}".format(alua_tpg.name)) lun.alua_tg_pt_gp_name = alua_tpg.name self.logger.debug("Bound {} on tpg{} to {}".format( stg_object.name, tpg.tag, alua_tpg.name))