Add new attributes to trunk model
This patch adds the following attributes to the trunk model:
* name: this is added for convenience, especially to speed
up resource lookup via CLI commands. This is also added
for consistency with other Neutron resources.
* admin_state_up: this is added for management needs. There
may be maintenance situations where preventing the user
from adding/removing subports to a trunk while in disabled
state is desired.
* status: this can be used to track the aggregate status
of all the resources (parent + subports) participating
into a trunk.
The API extension is modified accordingly, coverage added.
The hash for the trunk object is revised, while the object
version is left as is, since all of this is still unreleased.
The patch leaves the logic to handle the trunk status aggregation
to be added at a later date, whilst minor refactoring
improves readability and use of the database sessions.
Partially-implements: blueprint vlan-aware-vms
Change-Id: Ibe39378d43b1d63c2b006c2da574f52d9934a0df
diff --git a/neutron/tests/tempest/api/test_trunk.py b/neutron/tests/tempest/api/test_trunk.py
index d1fa325..05e1430 100644
--- a/neutron/tests/tempest/api/test_trunk.py
+++ b/neutron/tests/tempest/api/test_trunk.py
@@ -55,10 +55,10 @@
trunks_cleanup(cls.client, cls.trunks)
super(TrunkTestJSONBase, cls).resource_cleanup()
- def _create_trunk_with_network_and_parent(self, subports):
+ def _create_trunk_with_network_and_parent(self, subports, **kwargs):
network = self.create_network()
parent_port = self.create_port(network)
- trunk = self.client.create_trunk(parent_port['id'], subports)
+ trunk = self.client.create_trunk(parent_port['id'], subports, **kwargs)
self.trunks.append(trunk['trunk'])
return trunk
@@ -88,6 +88,20 @@
self.client.delete_trunk(trunk_id)
self.assertRaises(lib_exc.NotFound, self.client.show_trunk, trunk_id)
+ @test.idempotent_id('4ce46c22-a2b6-4659-bc5a-0ef2463cab32')
+ def test_create_update_trunk(self):
+ trunk = self._create_trunk_with_network_and_parent(None)
+ trunk_id = trunk['trunk']['id']
+ res = self.client.show_trunk(trunk_id)
+ self.assertTrue(res['trunk']['admin_state_up'])
+ self.assertEqual("", res['trunk']['name'])
+ res = self.client.update_trunk(
+ trunk_id, name='foo', admin_state_up=False)
+ self.assertFalse(res['trunk']['admin_state_up'])
+ self.assertEqual("foo", res['trunk']['name'])
+ # enable the trunk so that it can be managed
+ self.client.update_trunk(trunk_id, admin_state_up=True)
+
@test.idempotent_id('73365f73-bed6-42cd-960b-ec04e0c99d85')
def test_list_trunks(self):
trunk1 = self._create_trunk_with_network_and_parent(None)
@@ -162,7 +176,6 @@
class TrunksSearchCriteriaTest(base.BaseSearchCriteriaTest):
resource = 'trunk'
- field = 'id'
@classmethod
def skip_checks(cls):
@@ -178,7 +191,7 @@
net = cls.create_network(network_name='trunk-search-test-net')
for name in cls.resource_names:
parent_port = cls.create_port(net)
- trunk = cls.client.create_trunk(parent_port['id'], [])
+ trunk = cls.client.create_trunk(parent_port['id'], [], name=name)
cls.trunks.append(trunk['trunk'])
@classmethod
diff --git a/neutron/tests/tempest/api/test_trunk_negative.py b/neutron/tests/tempest/api/test_trunk_negative.py
index 556c374..16a9af3 100644
--- a/neutron/tests/tempest/api/test_trunk_negative.py
+++ b/neutron/tests/tempest/api/test_trunk_negative.py
@@ -128,6 +128,45 @@
'segmentation_id': 2}])
@test.attr(type='negative')
+ @test.idempotent_id('7f132ccc-1380-42d8-9c44-50411612bd01')
+ def test_add_subport_port_id_disabled_trunk(self):
+ trunk = self._create_trunk_with_network_and_parent(
+ None, admin_state_up=False)
+ self.assertRaises(lib_exc.Conflict,
+ self.client.add_subports,
+ trunk['trunk']['id'],
+ [{'port_id': trunk['trunk']['port_id'],
+ 'segmentation_type': 'vlan',
+ 'segmentation_id': 2}])
+ self.client.update_trunk(
+ trunk['trunk']['id'], admin_state_up=True)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('8f132ccc-1380-42d8-9c44-50411612bd01')
+ def test_remove_subport_port_id_disabled_trunk(self):
+ trunk = self._create_trunk_with_network_and_parent(
+ None, admin_state_up=False)
+ self.assertRaises(lib_exc.Conflict,
+ self.client.remove_subports,
+ trunk['trunk']['id'],
+ [{'port_id': trunk['trunk']['port_id'],
+ 'segmentation_type': 'vlan',
+ 'segmentation_id': 2}])
+ self.client.update_trunk(
+ trunk['trunk']['id'], admin_state_up=True)
+
+ @test.attr(type='negative')
+ @test.idempotent_id('9f132ccc-1380-42d8-9c44-50411612bd01')
+ def test_delete_trunk_disabled_trunk(self):
+ trunk = self._create_trunk_with_network_and_parent(
+ None, admin_state_up=False)
+ self.assertRaises(lib_exc.Conflict,
+ self.client.delete_trunk,
+ trunk['trunk']['id'])
+ self.client.update_trunk(
+ trunk['trunk']['id'], admin_state_up=True)
+
+ @test.attr(type='negative')
@test.idempotent_id('00cb40bb-1593-44c8-808c-72b47e64252f')
def test_add_subport_duplicate_segmentation_details(self):
trunk = self._create_trunk_with_network_and_parent(None)
diff --git a/neutron/tests/tempest/services/network/json/network_client.py b/neutron/tests/tempest/services/network/json/network_client.py
index 3220604..36a7f5b 100644
--- a/neutron/tests/tempest/services/network/json/network_client.py
+++ b/neutron/tests/tempest/services/network/json/network_client.py
@@ -659,7 +659,8 @@
body = jsonutils.loads(body)
return service_client.ResponseBody(resp, body)
- def create_trunk(self, parent_port_id, subports, tenant_id=None):
+ def create_trunk(self, parent_port_id, subports,
+ tenant_id=None, name=None, admin_state_up=None):
uri = '%s/trunks' % self.uri_prefix
post_data = {
'trunk': {
@@ -670,11 +671,24 @@
post_data['trunk']['sub_ports'] = subports
if tenant_id is not None:
post_data['trunk']['tenant_id'] = tenant_id
+ if name is not None:
+ post_data['trunk']['name'] = name
+ if admin_state_up is not None:
+ post_data['trunk']['admin_state_up'] = admin_state_up
resp, body = self.post(uri, self.serialize(post_data))
body = self.deserialize_single(body)
self.expected_success(201, resp.status)
return service_client.ResponseBody(resp, body)
+ def update_trunk(self, trunk_id, **kwargs):
+ put_body = {'trunk': kwargs}
+ body = jsonutils.dumps(put_body)
+ uri = '%s/trunks/%s' % (self.uri_prefix, trunk_id)
+ resp, body = self.put(uri, body)
+ self.expected_success(200, resp.status)
+ body = jsonutils.loads(body)
+ return service_client.ResponseBody(resp, body)
+
def show_trunk(self, trunk_id):
uri = '%s/trunks/%s' % (self.uri_prefix, trunk_id)
resp, body = self.get(uri)