Merge "Supports filtering port by address"

This commit is contained in:
Jenkins 2014-04-11 11:04:42 +00:00 committed by Gerrit Code Review
commit bc0d9ccb29
3 changed files with 71 additions and 11 deletions

View File

@ -159,8 +159,9 @@ class PortsController(rest.RestController):
def __init__(self, from_nodes=False): def __init__(self, from_nodes=False):
self._from_nodes = from_nodes self._from_nodes = from_nodes
def _get_ports_collection(self, node_uuid, marker, limit, sort_key, def _get_ports_collection(self, node_uuid, address, marker, limit,
sort_dir, expand=False, resource_url=None): sort_key, sort_dir, expand=False,
resource_url=None):
if self._from_nodes and not node_uuid: if self._from_nodes and not node_uuid:
raise exception.InvalidParameterValue(_( raise exception.InvalidParameterValue(_(
"Node id not specified.")) "Node id not specified."))
@ -178,6 +179,8 @@ class PortsController(rest.RestController):
marker_obj, marker_obj,
sort_key=sort_key, sort_key=sort_key,
sort_dir=sort_dir) sort_dir=sort_dir)
elif address:
ports = self._get_ports_by_address(address)
else: else:
ports = pecan.request.dbapi.get_port_list(limit, marker_obj, ports = pecan.request.dbapi.get_port_list(limit, marker_obj,
sort_key=sort_key, sort_key=sort_key,
@ -189,28 +192,46 @@ class PortsController(rest.RestController):
sort_key=sort_key, sort_key=sort_key,
sort_dir=sort_dir) sort_dir=sort_dir)
@wsme_pecan.wsexpose(PortCollection, types.uuid, types.uuid, int, def _get_ports_by_address(self, address):
wtypes.text, wtypes.text) """Retrieve a port by its address.
def get_all(self, node_uuid=None, marker=None, limit=None,
:param address: MAC address of a port, to get the port which has
this MAC address.
:returns: a list with the port, or an empty list if no port is found.
"""
try:
port = pecan.request.dbapi.get_port(address)
return [port]
except exception.PortNotFound:
return []
@wsme_pecan.wsexpose(PortCollection, types.uuid, types.macaddress,
types.uuid, int, wtypes.text, wtypes.text)
def get_all(self, node_uuid=None, address=None, marker=None, limit=None,
sort_key='id', sort_dir='asc'): sort_key='id', sort_dir='asc'):
"""Retrieve a list of ports. """Retrieve a list of ports.
:param node_uuid: UUID of a node, to get only ports for that node. :param node_uuid: UUID of a node, to get only ports for that node.
:param address: MAC address of a port, to get the port which has
this MAC address.
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id. :param sort_key: column to sort results by. Default: id.
:param sort_dir: direction to sort. "asc" or "desc". Default: asc. :param sort_dir: direction to sort. "asc" or "desc". Default: asc.
""" """
return self._get_ports_collection(node_uuid, marker, limit, return self._get_ports_collection(node_uuid, address, marker, limit,
sort_key, sort_dir) sort_key, sort_dir)
@wsme_pecan.wsexpose(PortCollection, types.uuid, types.uuid, int, @wsme_pecan.wsexpose(PortCollection, types.uuid, types.macaddress,
wtypes.text, wtypes.text) types.uuid, int, wtypes.text, wtypes.text)
def detail(self, node_uuid=None, marker=None, limit=None, def detail(self, node_uuid=None, address=None, marker=None, limit=None,
sort_key='id', sort_dir='asc'): sort_key='id', sort_dir='asc'):
"""Retrieve a list of ports with detail. """Retrieve a list of ports with detail.
:param node_uuid: UUID of a node, to get only ports for that node. :param node_uuid: UUID of a node, to get only ports for that node.
:param address: MAC address of a port, to get the port which has
this MAC address.
:param marker: pagination marker for large data sets. :param marker: pagination marker for large data sets.
:param limit: maximum number of resources to return in a single result. :param limit: maximum number of resources to return in a single result.
:param sort_key: column to sort results by. Default: id. :param sort_key: column to sort results by. Default: id.
@ -223,8 +244,9 @@ class PortsController(rest.RestController):
expand = True expand = True
resource_url = '/'.join(['ports', 'detail']) resource_url = '/'.join(['ports', 'detail'])
return self._get_ports_collection(node_uuid, marker, limit, sort_key, return self._get_ports_collection(node_uuid, address, marker, limit,
sort_dir, expand, resource_url) sort_key, sort_dir, expand,
resource_url)
@wsme_pecan.wsexpose(Port, types.uuid) @wsme_pecan.wsexpose(Port, types.uuid)
def get_one(self, port_uuid): def get_one(self, port_uuid):

View File

@ -28,6 +28,11 @@ class MacAddressType(wtypes.UserType):
basetype = wtypes.text basetype = wtypes.text
name = 'macaddress' name = 'macaddress'
# FIXME(lucasagomes): When used with wsexpose decorator WSME will try
# to get the name of the type by accessing it's __name__ attribute.
# Remove this __name__ attribute once it's fixed in WSME.
# https://bugs.launchpad.net/wsme/+bug/1265590
__name__ = name
@staticmethod @staticmethod
def validate(value): def validate(value):
@ -35,6 +40,8 @@ class MacAddressType(wtypes.UserType):
@staticmethod @staticmethod
def frombasetype(value): def frombasetype(value):
if value is None:
return None
return MacAddressType.validate(value) return MacAddressType.validate(value)

View File

@ -20,6 +20,7 @@ import datetime
import fixtures import fixtures
import mock import mock
from oslo.config import cfg from oslo.config import cfg
from testtools.matchers import HasLength
from ironic.common import utils from ironic.common import utils
from ironic.conductor import manager from ironic.conductor import manager
@ -141,6 +142,36 @@ class TestListPorts(base.FunctionalTest):
next_marker = data['ports'][-1]['uuid'] next_marker = data['ports'][-1]['uuid']
self.assertIn(next_marker, data['next']) self.assertIn(next_marker, data['next'])
def test_port_by_address(self):
address_template = "aa:bb:cc:dd:ee:f%d"
for id_ in range(3):
pdict = dbutils.get_test_port(id=id_,
uuid=utils.generate_uuid(),
address=address_template % id_)
self.dbapi.create_port(pdict)
target_address = address_template % 1
data = self.get_json('/ports?address=%s' % target_address)
self.assertThat(data['ports'], HasLength(1))
self.assertEqual(target_address, data['ports'][0]['address'])
def test_port_by_address_non_existent_address(self):
pdict = dbutils.get_test_port()
self.dbapi.create_port(pdict)
# non-existent address
data = self.get_json('/ports?address=%s' % 'aa:bb:cc:dd:ee:ff')
self.assertThat(data['ports'], HasLength(0))
def test_port_by_address_invalid_address_format(self):
pdict = dbutils.get_test_port()
self.dbapi.create_port(pdict)
invalid_address = 'invalid-mac-format'
response = self.get_json('/ports?address=%s' % invalid_address,
expect_errors=True)
self.assertEqual(400, response.status_int)
self.assertEqual('application/json', response.content_type)
self.assertIn(invalid_address, response.json['error_message'])
class TestPatch(base.FunctionalTest): class TestPatch(base.FunctionalTest):