Exemple #1
0
 def test_get_physnets_by_port_uuid_multiple_segments_no_physnet(
         self, mock_gp, mock_gn):
     port_uuid = 'fake-port-uuid'
     network_uuid = 'fake-network-uuid'
     mock_gp.return_value = {
         'network_id': network_uuid,
     }
     mock_gn.return_value = {
         'segments': [
             {
                 'provider:physical_network': None,
             },
             {
                 'provider:physical_network': None,
             },
         ],
     }
     result = neutron.get_physnets_by_port_uuid(self.client, port_uuid)
     mock_gp.assert_called_once_with(self.client,
                                     port_uuid,
                                     fields=self.PORT_FIELDS)
     mock_gn.assert_called_once_with(self.client,
                                     network_uuid,
                                     fields=self.NETWORK_FIELDS)
     self.assertEqual(set(), result)
Exemple #2
0
 def test_get_physnets_by_port_uuid_multiple_segments(self, mock_gp,
                                                      mock_gn):
     port_uuid = 'fake-port-uuid'
     network_uuid = 'fake-network-uuid'
     physnet1 = 'fake-physnet-1'
     physnet2 = 'fake-physnet-2'
     mock_gp.return_value = {
         'network_id': network_uuid,
     }
     mock_gn.return_value = {
         'segments': [
             {
                 'provider:physical_network': physnet1,
             },
             {
                 'provider:physical_network': physnet2,
             },
         ],
     }
     result = neutron.get_physnets_by_port_uuid(self.client,
                                                port_uuid)
     mock_gp.assert_called_once_with(self.client, port_uuid,
                                     fields=self.PORT_FIELDS)
     mock_gn.assert_called_once_with(self.client, network_uuid,
                                     fields=self.NETWORK_FIELDS)
     self.assertEqual({physnet1, physnet2}, result)
Exemple #3
0
 def test_get_physnets_by_port_uuid_single_segment(self, mock_gp, mock_gn):
     port_uuid = 'fake-port-uuid'
     network_uuid = 'fake-network-uuid'
     physnet = 'fake-physnet'
     mock_gp.return_value = {
         'network_id': network_uuid,
     }
     mock_gn.return_value = {
         'provider:physical_network': physnet,
     }
     result = neutron.get_physnets_by_port_uuid(self.client,
                                                port_uuid)
     mock_gp.assert_called_once_with(self.client, port_uuid,
                                     fields=self.PORT_FIELDS)
     mock_gn.assert_called_once_with(self.client, network_uuid,
                                     fields=self.NETWORK_FIELDS)
     self.assertEqual({physnet}, result)
Exemple #4
0
 def test_get_physnets_by_port_uuid_single_segment_no_physnet(
         self, mock_gp, mock_gn):
     port_uuid = 'fake-port-uuid'
     network_uuid = 'fake-network-uuid'
     mock_gp.return_value = {
         'network_id': network_uuid,
     }
     mock_gn.return_value = {
         'provider:physical_network': None,
     }
     result = neutron.get_physnets_by_port_uuid(self.client,
                                                port_uuid)
     mock_gp.assert_called_once_with(self.client, port_uuid,
                                     fields=self.PORT_FIELDS)
     mock_gn.assert_called_once_with(self.client, network_uuid,
                                     fields=self.NETWORK_FIELDS)
     self.assertEqual(set(), result)
Exemple #5
0
    def vif_attach(self, task, vif_info):
        """Attach a virtual network interface to a node

        Attach a virtual interface to a node.  When selecting a port or
        portgroup to attach the virtual interface to, the following ordered
        criteria are applied:

        * Require ports or portgroups to have a physical network that is either
          None or one of the VIF's allowed physical networks.
        * Prefer ports or portgroups with a physical network field which is not
          None.
        * Prefer portgroups to ports.
        * Prefer ports with PXE enabled.

        :param task: A TaskManager instance.
        :param vif_info: a dictionary of information about a VIF.
             It must have an 'id' key, whose value is a unique
             identifier for that VIF.
        :raises: NetworkError, VifAlreadyAttached, NoFreePhysicalPorts
        :raises: PortgroupPhysnetInconsistent if one of the node's portgroups
                 has ports which are not all assigned the same physical
                 network.
        """
        vif_id = vif_info['id']
        client = neutron.get_client()

        # Determine whether any of the node's ports have a physical network. If
        # not, we don't need to check the VIF's network's physical networks as
        # they will not affect the VIF to port mapping.
        physnets = set()
        if any(port.physical_network is not None for port in task.ports):
            try:
                physnets = neutron.get_physnets_by_port_uuid(client, vif_id)
            except (exception.InvalidParameterValue, exception.NetworkError):
                # TODO(mgoddard): Remove this except clause and handle errors
                # properly. We can do this once a strategy has been determined
                # for handling the tempest VIF tests in an environment that
                # may not support neutron.
                # NOTE(sambetts): If a client error occurs this is because
                # either neutron doesn't exist because we're running in
                # standalone environment or we can't find a matching neutron
                # port which means a user might be requesting a non-neutron
                # port. Assume no physical network information exists in these
                # cases.
                pass

            if len(physnets) > 1:
                # NOTE(mgoddard): Neutron cannot currently handle hosts which
                # are mapped to multiple segments in the same routed network.
                node_physnets = network.get_physnets_for_node(task)
                if len(node_physnets.intersection(physnets)) > 1:
                    reason = _("Node has ports which map to multiple segments "
                               "of the routed network to which the VIF is "
                               "attached. Currently neutron only supports "
                               "hosts which map to one segment of a routed "
                               "network")
                    raise exception.VifInvalidForAttach(
                        node=task.node.uuid, vif=vif_id, reason=reason)

        port_like_obj = get_free_port_like_object(task, vif_id, physnets)

        # Address is optional for portgroups
        if port_like_obj.address:
            # Check if the requested vif_id is a neutron port. If it is
            # then attempt to update the port's MAC address.
            try:
                client.show_port(vif_id)
            except neutron_exceptions.NeutronClientException:
                # TODO(mgoddard): Remove this except clause and handle errors
                # properly. We can do this once a strategy has been determined
                # for handling the tempest VIF tests in an environment that
                # may not support neutron.
                # NOTE(sambetts): If a client error occurs this is because
                # either neutron doesn't exist because we're running in
                # standalone environment or we can't find a matching neutron
                # port which means a user might be requesting a non-neutron
                # port. So skip trying to update the neutron port MAC address
                # in these cases.
                pass
            else:
                try:
                    neutron.update_port_address(vif_id, port_like_obj.address)
                except exception.FailedToUpdateMacOnPort:
                    raise exception.NetworkError(_(
                        "Unable to attach VIF %(vif)s because Ironic can not "
                        "update Neutron port %(port)s MAC address to match "
                        "physical MAC address %(mac)s") % {
                            'vif': vif_id, 'port': vif_id,
                            'mac': port_like_obj.address})

        int_info = port_like_obj.internal_info
        int_info[TENANT_VIF_KEY] = vif_id
        port_like_obj.internal_info = int_info
        port_like_obj.save()
        # NOTE(vsaienko) allow to attach VIF to active instance.
        if task.node.provision_state == states.ACTIVE:
            plug_port_to_tenant_network(task, port_like_obj, client=client)
Exemple #6
0
    def vif_attach(self, task, vif_info):
        """Attach a virtual network interface to a node

        Attach a virtual interface to a node.  When selecting a port or
        portgroup to attach the virtual interface to, the following ordered
        criteria are applied:

        * Require ports or portgroups to have a physical network that is either
          None or one of the VIF's allowed physical networks.
        * Prefer ports or portgroups with a physical network field which is not
          None.
        * Prefer portgroups to ports.
        * Prefer ports with PXE enabled.

        :param task: A TaskManager instance.
        :param vif_info: a dictionary of information about a VIF.
             It must have an 'id' key, whose value is a unique
             identifier for that VIF.
        :raises: NetworkError, VifAlreadyAttached, NoFreePhysicalPorts
        :raises: PortgroupPhysnetInconsistent if one of the node's portgroups
                 has ports which are not all assigned the same physical
                 network.
        """
        vif_id = vif_info['id']
        client = neutron.get_client(context=task.context)

        # Determine whether any of the node's ports have a physical network. If
        # not, we don't need to check the VIF's network's physical networks as
        # they will not affect the VIF to port mapping.
        physnets = set()
        if any(port.physical_network is not None for port in task.ports):
            physnets = neutron.get_physnets_by_port_uuid(client, vif_id)

            if len(physnets) > 1:
                # NOTE(mgoddard): Neutron cannot currently handle hosts which
                # are mapped to multiple segments in the same routed network.
                node_physnets = network.get_physnets_for_node(task)
                if len(node_physnets.intersection(physnets)) > 1:
                    reason = _("Node has ports which map to multiple segments "
                               "of the routed network to which the VIF is "
                               "attached. Currently neutron only supports "
                               "hosts which map to one segment of a routed "
                               "network")
                    raise exception.VifInvalidForAttach(node=task.node.uuid,
                                                        vif=vif_id,
                                                        reason=reason)

        port_like_obj = get_free_port_like_object(task, vif_id, physnets)

        # Address is optional for portgroups
        if port_like_obj.address:
            try:
                neutron.update_port_address(vif_id,
                                            port_like_obj.address,
                                            context=task.context)
            except exception.FailedToUpdateMacOnPort:
                raise exception.NetworkError(
                    _("Unable to attach VIF %(vif)s because Ironic can not "
                      "update Neutron port %(port)s MAC address to match "
                      "physical MAC address %(mac)s") % {
                          'vif': vif_id,
                          'port': vif_id,
                          'mac': port_like_obj.address
                      })

        self._save_vif_to_port_like_obj(port_like_obj, vif_id)

        # NOTE(vsaienko) allow to attach VIF to active instance.
        if task.node.provision_state == states.ACTIVE:
            plug_port_to_tenant_network(task, port_like_obj, client=client)
Exemple #7
0
    def vif_attach(self, task, vif_info):
        """Attach a virtual network interface to a node

        Attach a virtual interface to a node.  When selecting a port or
        portgroup to attach the virtual interface to, the following ordered
        criteria are applied:

        * Require ports or portgroups to have a physical network that is either
          None or one of the VIF's allowed physical networks.
        * Prefer ports or portgroups with a physical network field which is not
          None.
        * Prefer portgroups to ports.
        * Prefer ports with PXE enabled.

        :param task: A TaskManager instance.
        :param vif_info: a dictionary of information about a VIF.
                         It must have an 'id' key, whose value is a unique
                         identifier for that VIF.
        :raises: NetworkError, VifAlreadyAttached, NoFreePhysicalPorts
        :raises: PortgroupPhysnetInconsistent if one of the node's portgroups
                 has ports which are not all assigned the same physical
                 network.
        """
        vif_id = vif_info['id']
        client = neutron.get_client(context=task.context)

        # Determine whether any of the node's ports have a physical network. If
        # not, we don't need to check the VIF's network's physical networks as
        # they will not affect the VIF to port mapping.
        physnets = set()
        if any(port.physical_network is not None for port in task.ports):
            physnets = neutron.get_physnets_by_port_uuid(client, vif_id)

            if len(physnets) > 1:
                # NOTE(mgoddard): Neutron cannot currently handle hosts which
                # are mapped to multiple segments in the same routed network.
                node_physnets = network.get_physnets_for_node(task)
                if len(node_physnets.intersection(physnets)) > 1:
                    reason = _("Node has ports which map to multiple segments "
                               "of the routed network to which the VIF is "
                               "attached. Currently neutron only supports "
                               "hosts which map to one segment of a routed "
                               "network")
                    raise exception.VifInvalidForAttach(
                        node=task.node.uuid, vif=vif_id, reason=reason)

        port_like_obj = get_free_port_like_object(task, vif_id, physnets)

        # Address is optional for portgroups
        if port_like_obj.address:
            try:
                neutron.update_port_address(vif_id, port_like_obj.address,
                                            context=task.context)
            except exception.FailedToUpdateMacOnPort:
                raise exception.NetworkError(_(
                    "Unable to attach VIF %(vif)s because Ironic can not "
                    "update Neutron port %(port)s MAC address to match "
                    "physical MAC address %(mac)s") % {
                        'vif': vif_id, 'port': vif_id,
                        'mac': port_like_obj.address})

        self._save_vif_to_port_like_obj(port_like_obj, vif_id)

        # NOTE(vsaienko) allow to attach VIF to active instance.
        if task.node.provision_state == states.ACTIVE:
            plug_port_to_tenant_network(task, port_like_obj, client=client)
Exemple #8
0
    def vif_attach(self, task, vif_info):
        """Attach a virtual network interface to a node

        Attach a virtual interface to a node.  When selecting a port or
        portgroup to attach the virtual interface to, the following ordered
        criteria are applied:

        * Require ports or portgroups to have a physical network that is either
          None or one of the VIF's allowed physical networks.
        * Prefer ports or portgroups with a physical network field which is not
          None.
        * Prefer portgroups to ports.
        * Prefer ports with PXE enabled.

        :param task: A TaskManager instance.
        :param vif_info: a dictionary of information about a VIF.
             It must have an 'id' key, whose value is a unique
             identifier for that VIF.
        :raises: NetworkError, VifAlreadyAttached, NoFreePhysicalPorts
        :raises: PortgroupPhysnetInconsistent if one of the node's portgroups
                 has ports which are not all assigned the same physical
                 network.
        """
        vif_id = vif_info['id']
        client = neutron.get_client()

        # Determine whether any of the node's ports have a physical network. If
        # not, we don't need to check the VIF's network's physical networks as
        # they will not affect the VIF to port mapping.
        physnets = set()
        if any(port.physical_network is not None for port in task.ports):
            try:
                physnets = neutron.get_physnets_by_port_uuid(client, vif_id)
            except (exception.InvalidParameterValue, exception.NetworkError):
                # TODO(mgoddard): Remove this except clause and handle errors
                # properly. We can do this once a strategy has been determined
                # for handling the tempest VIF tests in an environment that
                # may not support neutron.
                # NOTE(sambetts): If a client error occurs this is because
                # either neutron doesn't exist because we're running in
                # standalone environment or we can't find a matching neutron
                # port which means a user might be requesting a non-neutron
                # port. Assume no physical network information exists in these
                # cases.
                pass

            if len(physnets) > 1:
                # NOTE(mgoddard): Neutron cannot currently handle hosts which
                # are mapped to multiple segments in the same routed network.
                node_physnets = network.get_physnets_for_node(task)
                if len(node_physnets.intersection(physnets)) > 1:
                    reason = _("Node has ports which map to multiple segments "
                               "of the routed network to which the VIF is "
                               "attached. Currently neutron only supports "
                               "hosts which map to one segment of a routed "
                               "network")
                    raise exception.VifInvalidForAttach(node=task.node.uuid,
                                                        vif=vif_id,
                                                        reason=reason)

        port_like_obj = get_free_port_like_object(task, vif_id, physnets)

        # Address is optional for portgroups
        if port_like_obj.address:
            # Check if the requested vif_id is a neutron port. If it is
            # then attempt to update the port's MAC address.
            try:
                client.show_port(vif_id)
            except neutron_exceptions.NeutronClientException:
                # TODO(mgoddard): Remove this except clause and handle errors
                # properly. We can do this once a strategy has been determined
                # for handling the tempest VIF tests in an environment that
                # may not support neutron.
                # NOTE(sambetts): If a client error occurs this is because
                # either neutron doesn't exist because we're running in
                # standalone environment or we can't find a matching neutron
                # port which means a user might be requesting a non-neutron
                # port. So skip trying to update the neutron port MAC address
                # in these cases.
                pass
            else:
                try:
                    neutron.update_port_address(vif_id, port_like_obj.address)
                except exception.FailedToUpdateMacOnPort:
                    raise exception.NetworkError(
                        _("Unable to attach VIF %(vif)s because Ironic can not "
                          "update Neutron port %(port)s MAC address to match "
                          "physical MAC address %(mac)s") % {
                              'vif': vif_id,
                              'port': vif_id,
                              'mac': port_like_obj.address
                          })

        int_info = port_like_obj.internal_info
        int_info[TENANT_VIF_KEY] = vif_id
        port_like_obj.internal_info = int_info
        port_like_obj.save()
        # NOTE(vsaienko) allow to attach VIF to active instance.
        if task.node.provision_state == states.ACTIVE:
            plug_port_to_tenant_network(task, port_like_obj, client=client)