Implement port api action
Jobs have done in this patch 1. API to retrieve list of ports: Done 2. API to retrieve details of a single port: Done 3. API to create (insert) a new port: Done 4. API to update an existing port: Done 5. API and RPC to delete an existing port: Done 6. DB API of get_port_list and tests Change-Id: Idd8c4ab9bc9e1eac2c0c93dfa699c81070f5fbe8
This commit is contained in:
parent
34823e35c8
commit
68bbcb7255
|
@ -15,9 +15,11 @@
|
|||
# under the License.
|
||||
|
||||
from ironic.api.controllers.v1 import node
|
||||
from ironic.api.controllers.v1 import port
|
||||
|
||||
|
||||
class Controller(object):
|
||||
"""Version 1 API controller root."""
|
||||
|
||||
nodes = node.NodesController()
|
||||
ports = port.PortsController()
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 UnitedStack Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
|
||||
from ironic.api.controllers.v1 import base
|
||||
from ironic import objects
|
||||
from ironic.openstack.common import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class Port(base.APIBase):
|
||||
"""API representation of a port.
|
||||
|
||||
This class enforces type checking and value constraints, and converts
|
||||
between the internal object model and the API representation of a port.
|
||||
"""
|
||||
|
||||
# NOTE: translate 'id' publicly to 'uuid' internally
|
||||
uuid = wtypes.text
|
||||
address = wtypes.text
|
||||
|
||||
# NOTE: translate 'extra' internally to 'meta_data' externally
|
||||
extra = {wtypes.text: wtypes.text}
|
||||
|
||||
node_id = int
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = objects.Port.fields.keys()
|
||||
for k in self.fields:
|
||||
setattr(self, k, kwargs.get(k))
|
||||
|
||||
|
||||
class PortsController(rest.RestController):
|
||||
"""REST controller for Ports."""
|
||||
|
||||
@wsme_pecan.wsexpose([unicode])
|
||||
def get_all(self):
|
||||
"""Retrieve a list of ports."""
|
||||
return pecan.request.dbapi.get_port_list()
|
||||
|
||||
@wsme_pecan.wsexpose(Port, unicode)
|
||||
def get_one(self, uuid):
|
||||
"""Retrieve information about the given port."""
|
||||
port = objects.Port.get_by_uuid(pecan.request.context, uuid)
|
||||
return port
|
||||
|
||||
@wsme.validate(Port)
|
||||
@wsme_pecan.wsexpose(Port, body=Port)
|
||||
def post(self, port):
|
||||
"""Ceate a new port."""
|
||||
try:
|
||||
new_port = pecan.request.dbapi.create_port(port.as_dict())
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
raise wsme.exc.ClientSideError(_("Invalid data"))
|
||||
return new_port
|
||||
|
||||
@wsme.validate(Port)
|
||||
@wsme_pecan.wsexpose(Port, unicode, body=Port)
|
||||
def patch(self, uuid, port_data):
|
||||
"""Update an existing port."""
|
||||
# TODO(wentian): add rpc handle,
|
||||
# eg. if update fails because node is already locked
|
||||
port = objects.Port.get_by_uuid(pecan.request.context, uuid)
|
||||
nn_delta_p = port_data.as_terse_dict()
|
||||
for k in nn_delta_p:
|
||||
port[k] = nn_delta_p[k]
|
||||
port.save()
|
||||
return port
|
||||
|
||||
@wsme_pecan.wsexpose(None, unicode, status_code=204)
|
||||
def delete(self, port_id):
|
||||
"""Delete a port."""
|
||||
pecan.request.dbapi.destroy_port(port_id)
|
|
@ -170,6 +170,13 @@ class Connection(object):
|
|||
:returns: A port.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_port_list(self):
|
||||
"""Return a lists of port
|
||||
|
||||
:return: Port list.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_ports_by_node(self, node):
|
||||
"""List all the ports for a given node.
|
||||
|
|
|
@ -293,6 +293,10 @@ class Connection(api.Connection):
|
|||
def get_port_by_vif(self, vif):
|
||||
pass
|
||||
|
||||
def get_port_list(self):
|
||||
query = model_query(models.Port.uuid)
|
||||
return [i[0] for i in query.all()]
|
||||
|
||||
@objects.objectify(objects.Port)
|
||||
def get_ports_by_node(self, node):
|
||||
query = model_query(models.Port)
|
||||
|
@ -302,6 +306,10 @@ class Connection(api.Connection):
|
|||
|
||||
@objects.objectify(objects.Port)
|
||||
def create_port(self, values):
|
||||
if not values.get('uuid'):
|
||||
values['uuid'] = uuidutils.generate_uuid()
|
||||
if not values.get('extra'):
|
||||
values['extra'] = '{}'
|
||||
port = models.Port()
|
||||
port.update(values)
|
||||
port.save()
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
from ironic.common import exception
|
||||
from ironic.db import api as dbapi
|
||||
from ironic.openstack.common import uuidutils
|
||||
from ironic.tests.db import base
|
||||
from ironic.tests.db import utils
|
||||
|
||||
|
@ -33,18 +34,31 @@ class DbPortTestCase(base.DbTestCase):
|
|||
|
||||
self.n = utils.get_test_node()
|
||||
self.p = utils.get_test_port()
|
||||
self.dbapi.create_node(self.n)
|
||||
self.dbapi.create_port(self.p)
|
||||
|
||||
def test_get_port_by_id(self):
|
||||
self.dbapi.create_port(self.p)
|
||||
res = self.dbapi.get_port(self.p['id'])
|
||||
self.assertEqual(self.p['address'], res['address'])
|
||||
|
||||
def test_get_port_by_uuid(self):
|
||||
self.dbapi.create_port(self.p)
|
||||
res = self.dbapi.get_port(self.p['uuid'])
|
||||
self.assertEqual(self.p['id'], res['id'])
|
||||
|
||||
def test_get_port_list(self):
|
||||
uuids = []
|
||||
for i in xrange(1, 6):
|
||||
n = utils.get_test_port(id=i, uuid=uuidutils.generate_uuid())
|
||||
self.dbapi.create_port(n)
|
||||
uuids.append(unicode(n['uuid']))
|
||||
res = self.dbapi.get_port_list()
|
||||
uuids.sort()
|
||||
res.sort()
|
||||
self.assertEqual(uuids, res)
|
||||
|
||||
def test_get_port_by_address(self):
|
||||
self.dbapi.create_port(self.p)
|
||||
|
||||
res = self.dbapi.get_port(self.p['address'])
|
||||
self.assertEqual(self.p['id'], res['id'])
|
||||
|
||||
|
@ -56,14 +70,20 @@ class DbPortTestCase(base.DbTestCase):
|
|||
self.dbapi.get_port, 'not-a-mac')
|
||||
|
||||
def test_get_ports_by_node_id(self):
|
||||
self.dbapi.create_node(self.n)
|
||||
self.dbapi.create_port(self.p)
|
||||
res = self.dbapi.get_ports_by_node(self.n['id'])
|
||||
self.assertEqual(self.p['address'], res[0]['address'])
|
||||
|
||||
def test_get_ports_by_node_uuid(self):
|
||||
self.dbapi.create_node(self.n)
|
||||
self.dbapi.create_port(self.p)
|
||||
res = self.dbapi.get_ports_by_node(self.n['uuid'])
|
||||
self.assertEqual(self.p['address'], res[0]['address'])
|
||||
|
||||
def test_get_ports_by_node_that_does_not_exist(self):
|
||||
self.dbapi.create_node(self.n)
|
||||
self.dbapi.create_port(self.p)
|
||||
res = self.dbapi.get_ports_by_node(99)
|
||||
self.assertEqual(0, len(res))
|
||||
|
||||
|
@ -72,11 +92,13 @@ class DbPortTestCase(base.DbTestCase):
|
|||
self.assertEqual(0, len(res))
|
||||
|
||||
def test_destroy_port(self):
|
||||
self.dbapi.create_port(self.p)
|
||||
self.dbapi.destroy_port(self.p['id'])
|
||||
self.assertRaises(exception.PortNotFound,
|
||||
self.dbapi.destroy_port, self.p['id'])
|
||||
|
||||
def test_update_port(self):
|
||||
self.dbapi.create_port(self.p)
|
||||
old_address = self.p['address']
|
||||
new_address = 'ff.ee.dd.cc.bb.aa'
|
||||
|
||||
|
|
Loading…
Reference in New Issue