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)
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)
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)
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)
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)
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)
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)
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)