Пример #1
0
 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]
Пример #2
0
    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')
Пример #3
0
    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
Пример #4
0
    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))