コード例 #1
0
    def test_remove_vlan_from_nb_arb_vid(self, mock_reassign):
        """Attempt to remove an arbitrary VID off the network bridge."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_fo_resp

        # Run the remove of the VLAN.  Make sure it is invoked with a new
        # valid arbitrary PVID.
        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   '4094')
        self.assertEqual(1, mock_reassign.call_count)
        mock_reassign.assert_called_with(4094, 4093, mock.ANY)
コード例 #2
0
    def test_remove_vlan_from_nb_arb_vid(self, mock_reassign):
        """Attempt to remove an arbitrary VID off the network bridge."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_fo_resp

        # Run the remove of the VLAN.  Make sure it is invoked with a new
        # valid arbitrary PVID.
        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   '4094')
        self.assertEqual(1, mock_reassign.call_count)
        mock_reassign.assert_called_with(4094, 4093, mock.ANY)
コード例 #3
0
    def test_remove_vlan_from_nb_bad_vid(self):
        """Attempt to remove a VID that can't be taken off NB."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_resp

        # Should fail if fail_if_pvid set to True
        self.assertRaises(pvm_exc.PvidOfNetworkBridgeError,
                          net_br.remove_vlan_from_nb, self.adpt,
                          self.host_uuid, self.nb_uuid, 2227, True)

        # Should not fail if fail_if_pvid set to False, but shouldn't call
        # update either.
        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   '2227')
        self.assertEqual(0, self.adpt.update.call_count)
コード例 #4
0
    def test_remove_vlan_from_nb_bad_vid(self):
        """Attempt to remove a VID that can't be taken off NB."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_resp

        # Should fail if fail_if_pvid set to True
        self.assertRaises(pvm_exc.PvidOfNetworkBridgeError,
                          net_br.remove_vlan_from_nb, self.adpt,
                          self.host_uuid, self.nb_uuid, 2227, True)

        # Should not fail if fail_if_pvid set to False, but shouldn't call
        # update either.
        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   '2227')
        self.assertEqual(0, self.adpt.update.call_count)
コード例 #5
0
    def test_remove_vlan_from_nb(self):
        """Happy path testing of the remove VLAN from NB."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_resp

        def validate_update(*kargs, **kwargs):
            # Make sure the load groups are down to just 1 now.
            nb = kargs[0]
            self.assertEqual(0, len(nb.seas[0].addl_adpts))
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_update

        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   1000)
        self.assertEqual(1, self.adpt.update_by_path.call_count)
コード例 #6
0
    def test_remove_vlan_from_nb(self):
        """Happy path testing of the remove VLAN from NB."""
        # Mock Data
        self.adpt.read.return_value = self.mgr_nbr_resp

        def validate_update(*kargs, **kwargs):
            # Make sure the load groups are down to just 1 now.
            nb = kargs[0]
            self.assertEqual(0, len(nb.seas[0].addl_adpts))
            return nb.entry

        self.adpt.update_by_path.side_effect = validate_update

        net_br.remove_vlan_from_nb(self.adpt, self.host_uuid, self.nb_uuid,
                                   1000)
        self.assertEqual(1, self.adpt.update_by_path.call_count)
コード例 #7
0
    def _cleanup_unused_vlans(self, nb_wraps, nb_req_vlans):
        cur_delete = 0

        # 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]

            # 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 sorted(vlans_to_del):
                if cur_delete < 3:
                    LOG.warning(
                        "Cleaning up VLAN %s from the system. It is "
                        "no longer in use.", vlan_to_del)
                    net_br.remove_vlan_from_nb(self.adapter, self.host_uuid,
                                               nb.uuid, vlan_to_del)
                else:
                    # We don't want to block on optimization for too long.
                    # Each VLAN clean up can take ~2 seconds, so if we do
                    # three of them, then that blocks deploys for about 6
                    # seconds.  We generally don't clean out VLANs that often
                    # but just in case, we get a rush of them, this ensures
                    # we don't block provision requests that are actually going
                    # on in the system.
                    LOG.warning(
                        "System identified that VLAN %s is unused. However, "
                        "three VLAN clean ups have already occurred in this "
                        "pass. Will clean up in next optimization pass.",
                        vlan_to_del)
                cur_delete += 1
コード例 #8
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)
コード例 #9
0
    def heal_and_optimize(self, is_boot, prov_reqs, lpar_uuids, overall_cnas):
        """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.
        :param prov_reqs: A list of ProvisionRequest objects that represent
                          the Neutron ports that should exist on this system.
                          It may include ports that have already been
                          provisioned.  This method should make sure it calls
                          update_device_up/down afterwards.
        :param lpar_uuids: A list of the VM UUIDs for the REST API.
        :param overall_cnas: A list of the systems Client Network Adapters.
        """
        # 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()

        # Call down to the provision.  This will call device up on the
        # requests.
        self.provision_devices(prov_reqs)

        # Make sure that the provision requests VLAN is captured in the
        # nb_req_vlans list...so that the VLAN is not accidentally removed.
        for req in prov_reqs:
            nb_uuid, req_vlan = self._get_nb_and_vlan(req, emit_warnings=False)
            nb_req_vlans[nb_uuid].add(req_vlan)

        # 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 overall_cnas:
            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)