Пример #1
0
def _cleanup_network_associations(host_dom, net_assns, context, db_session):
    """
    This method will look at all NetworkAssociations on the system and move
    any associated with SEAs that are now gone (if the SEA has a
    failover SEA available).

    :param host_dom: Host DOM from the db.  At this point, it should match the
                     live topology and have been saved to the db.  Thus, we
                     can use it for setting and saving NetworkAssociations.
    :param net_assns: NetworkAssociations that existed before reconcile ran.
    :param context: Context to use for db operations
    :param db_session: Session to use for db operations
    """
    LOG.debug('Enter _cleanup_network_associations')

    # If we have associations to inspect, be sure all SEA chains up to date.
    # Do it outside the loop so we just rebuild them once, rather than every
    # time through the loop.
    if net_assns:
        host_dom.find_sea_chains(rebuild=True)
    else:
        # No associations.  Just return.
        LOG.debug('Exit _cleanup_network_associations, no associations')

    # Look for NetworkAssociations that need to be moved.
    for net_assn in net_assns:
        LOG.debug('Processing neutron network %s' % net_assn.neutron_net_id)

        # See what SEA this NetworkAssociation was originally on.
        orig_sea = net_assn.sea
        if orig_sea is None:
            LOG.debug('No SEA for neutron network %s, skipping.' %
                      net_assn.neutron_net_id)
            continue

        # Get the chain the original SEA is on.  Note, even if the original
        # SEA is no longer available (ie, its VIOS is RMC inactive), it should
        # still be found in a chain since chains include all available and
        # unavailable SEAs.  Note, we have to find the chain by the primary
        # VEA info (pvid, vswitch, num additional VEAs) because it's possible
        # the orig_sea no longer even exists in the dom (ie, the VIOS was
        # deleted altogether, not just rmc inactive).
        sea_chain = host_dom.find_sea_chain_by_pvea_info(orig_sea)

        # Now find the proper SEA to use (ie, highest priority SEA)
        sea_to_use = (sea_chain[0] if sea_chain else None)

        # sea_to_use will be None if the original SEA was deleted and it had
        # no failover SEAs (or it did, but they were all deleted, too).
        if sea_to_use is not None:
            if orig_sea != sea_to_use:
                LOG.info(_('Moving neutron network %(netid)s\'s association '
                           'from SEA %(sea)s on lpar %(lparid)d to SEA '
                           '%(sea_next)s on lpar %(lpar_next)d' %
                           {'netid': net_assn.neutron_net_id,
                            'sea': orig_sea.name,
                            'lparid': net_assns[net_assn],
                            'sea_next': sea_to_use.name,
                            'lpar_next': sea_to_use.vio_server.lpar_id}))
                db.network_association_put_sea(context,
                                               host_dom.host_name,
                                               net_assn.neutron_net_id,
                                               sea_to_use,
                                               db_session)
            else:
                LOG.debug('Neutron network %s already associated properly'
                          % net_assn.neutron_net_id)
        else:
            LOG.warning(_('Unable to find new SEA for neutron network '
                          '%(netid)s that was originally on sea %(sea)s, '
                          'lpar %(lparid)d' %
                          {'netid': net_assn.neutron_net_id,
                           'sea': orig_sea.name,
                           'lparid': net_assns[net_assn]}))

    LOG.debug('Exit _cleanup_network_associations')
Пример #2
0
    def _get_specific_host_seas(self, context, host, vswitch=None, vlan=None,
                                net_id=None, session=None, ports=None):
        """
        This method will return the SEA candidates for a given host, and only
        that host.

        The format of the response will be:
        {
         "host_name": "host2",
         "adapters": [
            {
             "default": true,
             "sea_name": "ent5",
             "vswitch": "ETHERNET0",
             "lpar_id": 1,
             "ha_lpar_id": null,
             "ha_mode": "disabled",
             "pvid": 1,
             "state": "Available",
             "ha_state": null,
             "lpar_name": "15-34B9Z",
             "ha_lpar_name": null,
             "ha_sea": null
            }
         ]
        }

        :param context: The context for the request.
        :param host: The host name (as a string)
        :param vswitch: The vswitch that should be used to help identify the
                        default adapter.  If set to None all of the vSwitches
                        will be utilized.
        :param vlan: The vlan that should be used to help identify the default
                     adapter.  If set to None (the default value), a VLAN ID of
                     1 will be used.
        :param net_id: The network UUID of a neutron Network. This is optional
        :param ports: An optional list of ports for the specified network.
        """
        # Build basic data to determine targets
        vio_servers = dom_api.vio_server_find_all(context, host, session)
        host_dom = dom_model.Host(host, vio_servers)
        vswitches = self._get_vswitches(host_dom.find_all_primary_seas())

        # If the network id was set, then we should always use that networks
        # vlan id instead of the passed in value.
        vlan = self._determine_vlan(vlan, net_id, host, context)

        # We need to determine if this network has any VMs on the host.  If so,
        # then we can't be set to Do not Use.  We also can't allow them to
        # change vSwitches.
        allow_do_not_use_option = False
        if net_id:
            # We only allow the do not use option if the VM count for this
            # network is 0.  Otherwise a VM is using it, and we can't flip
            # to do not use until all the VMs are done.
            vm_list = dom_api.instances_find(context, host, net_id, ports)
            allow_do_not_use_option = (len(vm_list) == 0)

            # As noted above...if the network association has VMs, then we
            # can't let the user change the vSwitch that the networks are on.
            # Therefore, set the specific_vswitch so that the candidate_sea
            # loop won't take any other vSwitches into account.
            if len(vm_list) > 0:
                net_assn = dom_api.network_association_find(context,
                                                            host_dom.host_name,
                                                            net_id, session)

                # If there is a network association, just override the vSwitch
                # list with the network associations vSwitch.  This limits it
                # to a single vSwitch search scope.
                if net_assn and net_assn.sea:
                    vswitches = [net_assn.sea.primary_vea.vswitch_name]
        else:
            # If there was not a network id, then we assume that this is a
            # new network and therefore do not use should always be returned.
            allow_do_not_use_option = True

        # Variable to store all candidate SEAs
        candidate_seas = []

        # Walk through the vswitches on this host and determine the valid
        # candidates (broken into pools defined by the vswitches).
        for vswitch_name in vswitches:
            # If the user passed in a vswitch, and we don't match, continue
            if vswitch is not None and vswitch != vswitch_name:
                continue

            # Extend the candidates
            candidate_seas.extend(self._get_candidate_seas_for_vswitch(
                host_dom, vswitch_name, vlan))

        # Now we need to find the default adapter...may be None, which
        # indicates that it is a do not use.
        default_sea = self._find_default_adapter(host_dom, candidate_seas,
                                                 net_id, vlan, context,
                                                 session)
        # If the default sea is not selected, and there's only one vswitch
        # we need to determine a default adapter for this VLAN and create
        # that relationship.
        if(default_sea is None and not allow_do_not_use_option and net_id):
            vswitch_with_vlan = []
            for vswitch in vswitches:
                sea = host_dom.find_sea_for_vlan_vswitch(vlan, vswitch)
                if sea:
                    vswitch_with_vlan.append(sea)
            # We would like to set this as the default since in this
            # present call to host-seas - we need to report a default
            if len(vswitch_with_vlan) == 1:
                default_sea = vswitch_with_vlan[0]
                dom_api.network_association_put_sea(context, host, net_id,
                                                    vswitch_with_vlan[0],
                                                    session)

        # Now, build the adapter list to return
        adapter_list = []
        if allow_do_not_use_option or len(vswitches) > 1:
            adapter_list.append(self._format_sea_to_dict_response
                                (host_dom,
                                 None,
                                 default_sea is None))
        if default_sea and default_sea not in candidate_seas:
            candidate_seas.append(default_sea)
        for sea in candidate_seas:
            adapter_list.append(self._format_sea_to_dict_response
                                (host_dom, sea,
                                 default_sea == sea))

        msg = (ras.vif_get_msg('info', 'HOST_SEAS_RETURN') %
               {'vlan': vlan,
                'host_name': host,
                'list': adapter_list})
        ras.function_tracepoint(
            LOG, __name__, ras.TRACE_INFO, msg)
        return {
            'host_name': host_dom.host_name,
            'adapters': adapter_list
        }