Example #1
0
    def test_ensure_vlans_on_nb_new_vlan(self, mock_arb_vid, mock_find_vnet,
                                         mock_orphan_validate, mock_lock):
        """Validates new VLAN on existing Load Group."""
        # Build the responses
        self.adpt.read.side_effect = [
            self.mgr_nbr_resp, self.mgr_vsw_resp, self.mgr_vnet_resp
        ]
        mock_arb_vid.return_value = False
        mock_vnet = mock.MagicMock()
        mock_vnet.related_href = 'fake_href'
        mock_find_vnet.return_value = mock_vnet

        def validate_of_update_nb(*kargs, **kwargs):
            # Validate args
            nb = kargs[0]
            self.assertEqual(1, len(nb.load_grps[0].vnet_uri_list))
            self.assertEqual(2, len(nb.load_grps[1].vnet_uri_list))
            self.assertEqual(self.nb_uuid, nb.uuid)
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_of_update_nb

        # Invoke.  VLAN 2227 should be on there already.
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                  [2227, 2000])

        # Validate the calls
        self.assertEqual(1, self.adpt.update_by_path.call_count)
        self.assertEqual(1, mock_lock.call_count)
Example #2
0
    def test_ensure_vlans_on_nb_new_vlan(self, mock_arb_vid,
                                         mock_orphan_validate):
        """Validates new VLAN on existing Load Group."""
        # Build the responses
        self.adpt.read.side_effect = [
            self.mgr_nbr_resp, self.mgr_vsw_resp, self.mgr_vnet_resp
        ]
        mock_arb_vid.return_value = False

        def validate_of_update_nb(*kargs, **kwargs):
            # Validate args
            nb = kargs[0]
            self.assertEqual(0, len(nb.seas[0].primary_adpt.tagged_vlans))
            self.assertEqual(2, len(nb.seas[0].addl_adpts[0].tagged_vlans))
            self.assertEqual(self.nb_uuid, nb.uuid)
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_of_update_nb

        # Invoke.  VLAN 2227 should be on there already.
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                  [2227, 2000])

        # Validate the calls
        self.assertEqual(1, self.adpt.update_by_path.call_count)
    def test_ensure_vlans_on_nb_new_vlan(self, mock_arb_vid, mock_find_vnet,
                                         mock_orphan_validate):
        """Validates new VLAN on existing Load Group."""
        # Build the responses
        self.adpt.read.side_effect = [self.mgr_nbr_resp, self.mgr_vsw_resp,
                                      self.mgr_vnet_resp]
        mock_arb_vid.return_value = False
        mock_vnet = mock.MagicMock()
        mock_vnet.related_href = 'fake_href'
        mock_find_vnet.return_value = mock_vnet

        def validate_of_update_nb(*kargs, **kwargs):
            # Validate args
            nb = kargs[0]
            self.assertEqual(1, len(nb.load_grps[0].vnet_uri_list))
            self.assertEqual(2, len(nb.load_grps[1].vnet_uri_list))
            self.assertEqual(self.nb_uuid, nb.uuid)
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_of_update_nb

        # Invoke.  VLAN 2227 should be on there already.
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid,
                                  self.nb_uuid, [2227, 2000])

        # Validate the calls
        self.assertEqual(1, self.adpt.update_by_path.call_count)
Example #4
0
    def provision_devices(self, requests):
        """Will ensure that the VLANs are on the NBs for the edge devices.

        Takes in a set of ProvisionRequests.  From those devices, determines
        the correct network bridges and their appropriate VLANs.  Then calls
        down to the pypowervm API to ensure that the required VLANs are
        on the appropriate ports.

        Will also ensure that the client side adapter is updated with the
        correct VLAN.

        :param requests: A list of ProvisionRequest objects.
        """
        nb_to_vlan = {}
        for p_req in requests:
            # Break the ports into their respective lists broken down by
            # Network Bridge.
            nb_uuid, vlan = self._get_nb_and_vlan(p_req.rpc_device,
                                                  emit_warnings=True)

            # A warning message will be printed to user if this were to occur
            if nb_uuid is None:
                continue

            if nb_to_vlan.get(nb_uuid) is None:
                nb_to_vlan[nb_uuid] = set()

            nb_to_vlan[nb_uuid].add(vlan)

        # For each bridge, make sure the VLANs are serviced.
        for nb_uuid in nb_to_vlan.keys():
            net_br.ensure_vlans_on_nb(self.adapter, self.host_uuid, nb_uuid,
                                      nb_to_vlan.get(nb_uuid))

        # Now that the bridging is complete, loop through the devices again
        # and kick off the PVID update on the client devices.  This should
        # not be done until the vlan is on the network bridge.  Otherwise the
        # port state in the backing neutron server could be out of sync.
        for p_req in requests:
            self.pvid_updater.add(UpdateVLANRequest(p_req))
        LOG.debug('Successfully provisioned new devices.')
Example #5
0
    def test_ensure_vlan_on_nb_reassign(self, mock_support_vlan, mock_reassign,
                                        mock_orphan_validate, mock_orphans):
        """Validates that after update, we support the VLAN."""
        # Have the response
        self.adpt.read.return_value = self.mgr_nbr_resp

        # First call, say that we don't support the VLAN (which is true).
        # Second call, fake out that we now do.
        # Works in pairs, as there are two VLANs we're working through.
        mock_support_vlan.side_effect = [False, False, True, True]
        mock_orphans.return_value = []

        # Invoke
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                  [4093, 4094])
        self.assertEqual(2, self.adpt.read.call_count)
        self.assertEqual(1, mock_reassign.call_count)

        # Should be called re-assigning 4094 (old) to 4092.  Shouldn't be
        # 4093 as that is also an additional VLAN.
        mock_reassign.assert_called_once_with(4094, 4092, mock.ANY)
    def test_ensure_vlan_on_nb_reassign(
            self, mock_support_vlan, mock_reassign, mock_orphan_validate,
            mock_orphan_vlans):
        """Validates that after update, we support the VLAN."""
        # Have the response
        self.adpt.read.return_value = self.mgr_nbr_resp

        # First call, say that we don't support the VLAN (which is true).
        # Second call, fake out that we now do.
        # Need pairs, as there are two VLANs we are passing in.
        mock_support_vlan.side_effect = [False, False, True, True]
        mock_orphan_vlans.return_value = []

        # Invoke
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                  ['4093', 4094])
        self.assertEqual(2, self.adpt.read.call_count)
        self.assertEqual(1, mock_reassign.call_count)

        # Should be called re-assigning 4094 (old) to 4092.  Shouldn't be
        # 4093 as that is also an additional VLAN.
        mock_reassign.assert_called_once_with(4094, 4092, mock.ANY)
Example #7
0
    def provision_devices(self, requests):
        """Will ensure that the VLANs are on the NBs for the edge devices.

        Takes in a set of ProvisionRequests.  From those devices, determines
        the correct network bridges and their appropriate VLANs.  Then calls
        down to the pypowervm API to ensure that the required VLANs are
        on the appropriate ports.

        Will also ensure that the client side adapter is updated with the
        correct VLAN.

        :param requests: A list of ProvisionRequest objects.
        """
        # Only handle 'plug' requests.
        plug_reqs = {req for req in requests if req.action == preq.PLUG}
        nb_to_vlan = {}
        for p_req in plug_reqs:
            # Break the ports into their respective lists broken down by
            # Network Bridge.
            nb_uuid, vlan = self._get_nb_and_vlan(p_req.rpc_device,
                                                  emit_warnings=True)

            # A warning message will be printed to user if this were to occur
            if nb_uuid is None:
                continue

            if nb_to_vlan.get(nb_uuid) is None:
                nb_to_vlan[nb_uuid] = set()

            nb_to_vlan[nb_uuid].add(vlan)

        # For each bridge, make sure the VLANs are serviced.
        for nb_uuid in nb_to_vlan:
            net_br.ensure_vlans_on_nb(self.adapter, self.host_uuid, nb_uuid,
                                      nb_to_vlan.get(nb_uuid))

        # Now that the bridging is complete, let the superclass mark them as up
        super(SharedEthernetNeutronAgent, self).provision_devices(plug_reqs)
        LOG.debug('Successfully provisioned SEA VLANs for new devices.')
    def test_ensure_vlans_on_nb_new_vlan(self, mock_arb_vid,
                                         mock_orphan_validate):
        """Validates new VLAN on existing Load Group."""
        # Build the responses
        self.adpt.read.side_effect = [self.mgr_nbr_resp, self.mgr_vsw_resp,
                                      self.mgr_vnet_resp]
        mock_arb_vid.return_value = False

        def validate_of_update_nb(*kargs, **kwargs):
            # Validate args
            nb = kargs[0]
            self.assertEqual(0, len(nb.seas[0].primary_adpt.tagged_vlans))
            self.assertEqual(2, len(nb.seas[0].addl_adpts[0].tagged_vlans))
            self.assertEqual(self.nb_uuid, nb.uuid)
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_of_update_nb

        # Invoke.  VLAN 2227 should be on there already.
        net_br.ensure_vlans_on_nb(self.adpt, self.host_uuid,
                                  self.nb_uuid, [2227, 2000])

        # Validate the calls
        self.assertEqual(1, self.adpt.update_by_path.call_count)
Example #9
0
    def heal_and_optimize(self, is_boot):
        """Heals the system's network bridges and optimizes.

        Will query neutron for all the ports in use on this host.  Ensures that
        all of the VLANs needed for those ports are available on the correct
        network bridge.

        Finally, it optimizes the system by removing any VLANs that may no
        longer be required.  The VLANs that are removed must meet the following
        conditions:
         - Are not in use by ANY virtual machines on the system.  OpenStack
           managed or not.
         - Are not part of the primary load group on the Network Bridge.

        :param is_boot: Indicates if this is the first call on boot up of the
                        agent.
        """
        # List all our clients
        client_adpts = utils.list_cnas(self.adapter, self.host_uuid)

        # Get all the devices that Neutron knows for this host.  Note that
        # we pass in all of the macs on the system.  For VMs that neutron does
        # not know about, we get back an empty structure with just the mac.
        client_macs = [utils.norm_mac(x.mac) for x in client_adpts]
        devs = self.get_devices_details_list(client_macs)

        # Dictionary of the required VLANs on the Network Bridge
        nb_req_vlans = {}
        nb_wraps = utils.list_bridges(self.adapter, self.host_uuid)
        for nb_wrap in nb_wraps:
            nb_req_vlans[nb_wrap.uuid] = set()

        for dev in devs:
            nb_uuid, req_vlan = self._get_nb_and_vlan(dev, emit_warnings=False)

            # This can happen for ports that are on the host, but not in
            # Neutron.
            if nb_uuid is None or req_vlan is None:
                continue

            # If that list does not contain my VLAN, add it
            nb_req_vlans[nb_uuid].add(req_vlan)

        # Lets ensure that all VLANs for the openstack VMs are on the network
        # bridges.
        for nb_uuid in nb_req_vlans.keys():
            net_br.ensure_vlans_on_nb(self.adapter, self.host_uuid, nb_uuid,
                                      nb_req_vlans[nb_uuid])

        # We should clean up old VLANs as well.  However, we only want to clean
        # up old VLANs that are not in use by ANYTHING in the system.
        #
        # The first step is to identify the VLANs that are needed.  That can
        # be done by extending our nb_req_vlans map.
        #
        # We first extend that map by listing all the VMs on the system
        # (whether managed by OpenStack or not) and then seeing what Network
        # Bridge uses them.
        vswitch_map = utils.get_vswitch_map(self.adapter, self.host_uuid)
        for client_adpt in client_adpts:
            nb = utils.find_nb_for_cna(nb_wraps, client_adpt, vswitch_map)
            # Could occur if a system is internal only.
            if nb is None:
                LOG.debug("Client Adapter with mac %s is internal only.",
                          client_adpt.mac)
                continue

            # Make sure that it is on the nb_req_vlans list, as it is now
            # considered required.
            nb_req_vlans[nb.uuid].add(client_adpt.pvid)

            # Extend for each additional vlans as well
            for addl_vlan in client_adpt.tagged_vlans:
                nb_req_vlans[nb.uuid].add(addl_vlan)

        # We will have a list of CNAs that are not yet created, but are pending
        # provisioning from Nova.  Keep track of those so that we don't tear
        # those off the SEA.
        pending_vlans = self.pvid_updater.pending_vlans

        # The list of required VLANs on each network bridge also includes
        # everything on the primary VEA.
        for nb in nb_wraps:
            prim_ld_grp = nb.load_grps[0]
            vlans = [prim_ld_grp.pvid]
            vlans.extend(prim_ld_grp.tagged_vlans)
            for vlan in vlans:
                nb_req_vlans[nb.uuid].add(vlan)

        # If the configuration is set.
        if ACONF.automated_powervm_vlan_cleanup:
            # Loop through and remove VLANs that are no longer needed.
            for nb in nb_wraps:
                # Join the required vlans on the network bridge (already in
                # use) with the pending VLANs.
                req_vlans = nb_req_vlans[nb.uuid] | pending_vlans

                # Get ALL the VLANs on the bridge
                existing_vlans = set(nb.list_vlans())

                # To determine the ones no longer needed, subtract from all the
                # VLANs the ones that are no longer needed.
                vlans_to_del = existing_vlans - req_vlans
                for vlan_to_del in vlans_to_del:
                    LOG.warn(_LW("Cleaning up VLAN %(vlan)s from the system.  "
                                 "It is no longer in use."),
                             {'vlan': vlan_to_del})
                    net_br.remove_vlan_from_nb(self.adapter, self.host_uuid,
                                               nb.uuid, vlan_to_del)