Merge "Use association_proxy for port groups node_uuid"
This commit is contained in:
commit
c130d063b6
@ -163,22 +163,13 @@ def port_sanitize(port, fields=None):
|
|||||||
def list_convert_with_links(rpc_ports, limit, url, fields=None, **kwargs):
|
def list_convert_with_links(rpc_ports, limit, url, fields=None, **kwargs):
|
||||||
ports = []
|
ports = []
|
||||||
for rpc_port in rpc_ports:
|
for rpc_port in rpc_ports:
|
||||||
try:
|
port = convert_with_links(rpc_port, fields=fields,
|
||||||
port = convert_with_links(rpc_port, fields=fields,
|
sanitize=False)
|
||||||
sanitize=False)
|
# NOTE(dtantsur): node was deleted after we fetched the port
|
||||||
# NOTE(dtantsur): node was deleted after we fetched the port
|
# list, meaning that the port was also deleted. Skip it.
|
||||||
# list, meaning that the port was also deleted. Skip it.
|
if port['node_uuid'] is None:
|
||||||
if port['node_uuid'] is None:
|
continue
|
||||||
continue
|
|
||||||
except exception.PortgroupNotFound:
|
|
||||||
# NOTE(dtantsur): port group was deleted after we fetched the
|
|
||||||
# port list, it may mean that the port was deleted too, but
|
|
||||||
# we don't know it. Pretend that the port group was removed.
|
|
||||||
LOG.debug('Removing port group UUID from port %s as the port '
|
|
||||||
'group was deleted', rpc_port.uuid)
|
|
||||||
rpc_port.portgroup_id = None
|
|
||||||
port = convert_with_links(rpc_port, fields=fields,
|
|
||||||
sanitize=False)
|
|
||||||
ports.append(port)
|
ports.append(port)
|
||||||
return collection.list_convert_with_links(
|
return collection.list_convert_with_links(
|
||||||
items=ports,
|
items=ports,
|
||||||
|
@ -90,10 +90,10 @@ def convert_with_links(rpc_portgroup, fields=None, sanitize=True):
|
|||||||
'mode',
|
'mode',
|
||||||
'name',
|
'name',
|
||||||
'properties',
|
'properties',
|
||||||
'standalone_ports_supported'
|
'standalone_ports_supported',
|
||||||
|
'node_uuid'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
api_utils.populate_node_uuid(rpc_portgroup, portgroup)
|
|
||||||
url = api.request.public_url
|
url = api.request.public_url
|
||||||
portgroup['ports'] = [
|
portgroup['ports'] = [
|
||||||
link.make_link('self', url, 'portgroups',
|
link.make_link('self', url, 'portgroups',
|
||||||
|
@ -524,7 +524,7 @@ RELEASE_MAPPING = {
|
|||||||
'Deployment': ['1.0'],
|
'Deployment': ['1.0'],
|
||||||
'DeployTemplate': ['1.1'],
|
'DeployTemplate': ['1.1'],
|
||||||
'Port': ['1.11'],
|
'Port': ['1.11'],
|
||||||
'Portgroup': ['1.4'],
|
'Portgroup': ['1.5'],
|
||||||
'Trait': ['1.0'],
|
'Trait': ['1.0'],
|
||||||
'TraitList': ['1.0'],
|
'TraitList': ['1.0'],
|
||||||
'VolumeConnector': ['1.0'],
|
'VolumeConnector': ['1.0'],
|
||||||
|
@ -296,6 +296,15 @@ class Portgroup(Base):
|
|||||||
mode = Column(String(255))
|
mode = Column(String(255))
|
||||||
properties = Column(db_types.JsonEncodedDict)
|
properties = Column(db_types.JsonEncodedDict)
|
||||||
|
|
||||||
|
_node_uuid = orm.relationship(
|
||||||
|
"Node",
|
||||||
|
viewonly=True,
|
||||||
|
primaryjoin="(Node.id == Portgroup.node_id)",
|
||||||
|
lazy="selectin",
|
||||||
|
)
|
||||||
|
node_uuid = association_proxy(
|
||||||
|
"_node_uuid", "uuid", creator=lambda _i: Node(uuid=_i))
|
||||||
|
|
||||||
|
|
||||||
class NodeTag(Base):
|
class NodeTag(Base):
|
||||||
"""Represents a tag of a bare metal node."""
|
"""Represents a tag of a bare metal node."""
|
||||||
|
@ -36,7 +36,8 @@ class Portgroup(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
# Version 1.4: Migrate/copy extra['vif_port_id'] to
|
# Version 1.4: Migrate/copy extra['vif_port_id'] to
|
||||||
# internal_info['tenant_vif_port_id'] (not an explicit db
|
# internal_info['tenant_vif_port_id'] (not an explicit db
|
||||||
# change)
|
# change)
|
||||||
VERSION = '1.4'
|
# Version 1.5: Add node_uuid field
|
||||||
|
VERSION = '1.5'
|
||||||
|
|
||||||
dbapi = dbapi.get_instance()
|
dbapi = dbapi.get_instance()
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ class Portgroup(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
'uuid': object_fields.UUIDField(nullable=True),
|
'uuid': object_fields.UUIDField(nullable=True),
|
||||||
'name': object_fields.StringField(nullable=True),
|
'name': object_fields.StringField(nullable=True),
|
||||||
'node_id': object_fields.IntegerField(nullable=True),
|
'node_id': object_fields.IntegerField(nullable=True),
|
||||||
|
'node_uuid': object_fields.UUIDField(nullable=True),
|
||||||
'address': object_fields.MACAddressField(nullable=True),
|
'address': object_fields.MACAddressField(nullable=True),
|
||||||
'extra': object_fields.FlexibleDictField(nullable=True),
|
'extra': object_fields.FlexibleDictField(nullable=True),
|
||||||
'internal_info': object_fields.FlexibleDictField(nullable=True),
|
'internal_info': object_fields.FlexibleDictField(nullable=True),
|
||||||
@ -261,6 +263,10 @@ class Portgroup(base.IronicObject, object_base.VersionedObjectDictCompat):
|
|||||||
"""
|
"""
|
||||||
values = self.do_version_changes_for_db()
|
values = self.do_version_changes_for_db()
|
||||||
db_portgroup = self.dbapi.create_portgroup(values)
|
db_portgroup = self.dbapi.create_portgroup(values)
|
||||||
|
# NOTE(hjensas): To avoid lazy load issue (DetachedInstanceError) in
|
||||||
|
# sqlalchemy, get new port the port from the DB to ensure the node_uuid
|
||||||
|
# via association_proxy relationship is loaded.
|
||||||
|
db_portgroup = self.dbapi.get_portgroup_by_id(db_portgroup['id'])
|
||||||
self._from_db_object(self._context, self, db_portgroup)
|
self._from_db_object(self._context, self, db_portgroup)
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
|
@ -15,7 +15,6 @@ Tests for the API /ports/ methods.
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from http import client as http_client
|
from http import client as http_client
|
||||||
import types
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from urllib import parse as urlparse
|
from urllib import parse as urlparse
|
||||||
|
|
||||||
@ -236,24 +235,6 @@ class TestListPorts(test_api_base.BaseApiTest):
|
|||||||
# never expose the node_id
|
# never expose the node_id
|
||||||
self.assertNotIn('node_id', data['ports'][0])
|
self.assertNotIn('node_id', data['ports'][0])
|
||||||
|
|
||||||
# NOTE(jlvillal): autospec=True doesn't work on staticmethods:
|
|
||||||
# https://bugs.python.org/issue23078
|
|
||||||
@mock.patch.object(objects.Portgroup, 'get', spec_set=types.FunctionType)
|
|
||||||
def test_list_with_deleted_port_group(self, mock_get_pg):
|
|
||||||
# check that we don't end up with HTTP 400 when port group deletion
|
|
||||||
# races with listing ports - see https://launchpad.net/bugs/1748893
|
|
||||||
portgroup = obj_utils.create_test_portgroup(self.context,
|
|
||||||
node_id=self.node.id)
|
|
||||||
port = obj_utils.create_test_port(self.context, node_id=self.node.id,
|
|
||||||
portgroup_id=portgroup.id)
|
|
||||||
mock_get_pg.side_effect = exception.PortgroupNotFound('boom')
|
|
||||||
data = self.get_json(
|
|
||||||
'/ports/detail',
|
|
||||||
headers={api_base.Version.string: str(api_v1.max_version())}
|
|
||||||
)
|
|
||||||
self.assertEqual(port.uuid, data['ports'][0]["uuid"])
|
|
||||||
self.assertIsNone(data['ports'][0]["portgroup_uuid"])
|
|
||||||
|
|
||||||
@mock.patch.object(policy, 'authorize', spec=True)
|
@mock.patch.object(policy, 'authorize', spec=True)
|
||||||
def test_list_non_admin_forbidden(self, mock_authorize):
|
def test_list_non_admin_forbidden(self, mock_authorize):
|
||||||
def mock_authorize_function(rule, target, creds):
|
def mock_authorize_function(rule, target, creds):
|
||||||
|
@ -449,6 +449,8 @@ def get_test_portgroup(**kw):
|
|||||||
'uuid': kw.get('uuid', '6eb02b44-18a3-4659-8c0b-8d2802581ae4'),
|
'uuid': kw.get('uuid', '6eb02b44-18a3-4659-8c0b-8d2802581ae4'),
|
||||||
'name': kw.get('name', 'fooname'),
|
'name': kw.get('name', 'fooname'),
|
||||||
'node_id': kw.get('node_id', 123),
|
'node_id': kw.get('node_id', 123),
|
||||||
|
'node_uuid': kw.get('node_uuid',
|
||||||
|
'40481b96-306b-4a33-901f-795a3dc2f397'),
|
||||||
'address': kw.get('address', '52:54:00:cf:2d:31'),
|
'address': kw.get('address', '52:54:00:cf:2d:31'),
|
||||||
'extra': kw.get('extra', {}),
|
'extra': kw.get('extra', {}),
|
||||||
'created_at': kw.get('created_at'),
|
'created_at': kw.get('created_at'),
|
||||||
|
@ -680,7 +680,7 @@ expected_object_fingerprints = {
|
|||||||
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
||||||
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
||||||
'Port': '1.11-97bf15b61224f26c65e90f007d78bfd2',
|
'Port': '1.11-97bf15b61224f26c65e90f007d78bfd2',
|
||||||
'Portgroup': '1.4-71923a81a86743b313b190f5c675e258',
|
'Portgroup': '1.5-df4dc15967f67114d51176a98a901a83',
|
||||||
'Conductor': '1.3-d3f53e853b4d58cae5bfbd9a8341af4a',
|
'Conductor': '1.3-d3f53e853b4d58cae5bfbd9a8341af4a',
|
||||||
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
|
'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',
|
||||||
'NotificationPublisher': '1.0-51a09397d6c0687771fb5be9a999605d',
|
'NotificationPublisher': '1.0-51a09397d6c0687771fb5be9a999605d',
|
||||||
|
@ -80,13 +80,18 @@ class TestPortgroupObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
def test_create(self):
|
def test_create(self):
|
||||||
portgroup = objects.Portgroup(self.context, **self.fake_portgroup)
|
portgroup = objects.Portgroup(self.context, **self.fake_portgroup)
|
||||||
with mock.patch.object(self.dbapi, 'create_portgroup',
|
with mock.patch.object(self.dbapi, 'create_portgroup',
|
||||||
autospec=True) as mock_create_portgroup:
|
autospec=True) as mock_create_pg:
|
||||||
mock_create_portgroup.return_value = db_utils.get_test_portgroup()
|
with mock.patch.object(self.dbapi, 'get_portgroup_by_id',
|
||||||
|
autospec=True) as mock_get_pg:
|
||||||
|
test_pg = db_utils.get_test_portgroup()
|
||||||
|
mock_create_pg.return_value = test_pg
|
||||||
|
mock_get_pg.return_value = test_pg
|
||||||
|
mock_create_pg.return_value = db_utils.get_test_portgroup()
|
||||||
|
|
||||||
portgroup.create()
|
portgroup.create()
|
||||||
|
|
||||||
args, _kwargs = mock_create_portgroup.call_args
|
args, _kwargs = mock_create_pg.call_args
|
||||||
self.assertEqual(objects.Portgroup.VERSION, args[0]['version'])
|
self.assertEqual(objects.Portgroup.VERSION, args[0]['version'])
|
||||||
|
|
||||||
def test_save(self):
|
def test_save(self):
|
||||||
uuid = self.fake_portgroup['uuid']
|
uuid = self.fake_portgroup['uuid']
|
||||||
|
Loading…
x
Reference in New Issue
Block a user