1 From 89de63de05e296af583032cb17a3d76b4b4d6a40 Mon Sep 17 00:00:00 2001
2 From: Carlos Goncalves <carlos.goncalves@neclab.eu>
3 Date: Mon, 23 Jan 2017 19:53:04 +0000
4 Subject: [PATCH] Port data plane status extension implementation
6 Implements the port data plane status extension. Third parties
7 can report via Neutron API issues in the underlying data plane
8 affecting connectivity from/to Neutron ports.
11 - None: no status being reported; default value
12 - ACTIVE: all is up and running
13 - DOWN: no traffic can flow from/to the Neutron port
15 Setting attribute available to admin or any user with specific role
16 (default role: data_plane_integrator).
18 ML2 extension driver loaded on request via configuration:
21 extension_drivers = data_plane_status
26 DocImpact: users can get status of the underlying port data plane;
27 attribute writable by admin users and users granted the
28 'data-plane-integrator' role.
29 APIImpact: port now has data_plane_status attr, set on port update
31 Implements: blueprint port-data-plane-status
33 Depends-On: I04eef902b3310f799b1ce7ea44ed7cf77c74da04
34 Change-Id: Ic9e1e3ed9e3d4b88a4292114f4cb4192ac4b3502
36 neutron/db/data_plane_status_db.py | 48 ++++++++++++++++++++++
37 .../alembic_migrations/versions/EXPAND_HEAD | 2 +-
38 .../804a3c76314c_add_data_plane_status_to_port.py | 39 ++++++++++++++++++
39 neutron/db/models/data_plane_status.py | 34 +++++++++++++++
40 neutron/extensions/data_plane_status.py | 47 +++++++++++++++++++++
41 .../objects/port/extensions/data_plane_status.py | 37 +++++++++++++++++
42 neutron/objects/ports.py | 14 ++++++-
43 .../plugins/ml2/extensions/data_plane_status.py | 41 ++++++++++++++++++
44 8 files changed, 260 insertions(+), 2 deletions(-)
45 create mode 100644 neutron/db/data_plane_status_db.py
46 create mode 100644 neutron/db/migration/alembic_migrations/versions/pike/expand/804a3c76314c_add_data_plane_status_to_port.py
47 create mode 100644 neutron/db/models/data_plane_status.py
48 create mode 100644 neutron/extensions/data_plane_status.py
49 create mode 100644 neutron/objects/port/extensions/data_plane_status.py
50 create mode 100644 neutron/plugins/ml2/extensions/data_plane_status.py
52 diff --git a/neutron/db/data_plane_status_db.py b/neutron/db/data_plane_status_db.py
54 index 000000000..4e5c23aef
56 +++ b/neutron/db/data_plane_status_db.py
58 +# Copyright (c) 2017 NEC Corporation. All rights reserved.
60 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
61 +# not use this file except in compliance with the License. You may obtain
62 +# a copy of the License at
64 +# http://www.apache.org/licenses/LICENSE-2.0
66 +# Unless required by applicable law or agreed to in writing, software
67 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
68 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
69 +# License for the specific language governing permissions and limitations
72 +from neutron_lib.api.definitions import data_plane_status as dps_lib
74 +from neutron.objects.port.extensions import data_plane_status as dps_obj
77 +class DataPlaneStatusMixin(object):
78 + """Mixin class to add data plane status to a port"""
80 + def _process_create_port_data_plane_status(self, context, data, res):
81 + obj = dps_obj.PortDataPlaneStatus(context, port_id=res['id'],
82 + data_plane_status=data[dps_lib.DATA_PLANE_STATUS])
84 + res[dps_lib.DATA_PLANE_STATUS] = data[dps_lib.DATA_PLANE_STATUS]
86 + def _process_update_port_data_plane_status(self, context, data,
88 + if dps_lib.DATA_PLANE_STATUS not in data:
91 + obj = dps_obj.PortDataPlaneStatus.get_object(context,
94 + obj.data_plane_status = data[dps_lib.DATA_PLANE_STATUS]
96 + res[dps_lib.DATA_PLANE_STATUS] = data[dps_lib.DATA_PLANE_STATUS]
98 + self._process_create_port_data_plane_status(context, data, res)
100 + def _extend_port_data_plane_status(self, port_res, port_db):
101 + port_res[dps_lib.DATA_PLANE_STATUS] = None
103 + if port_db.get(dps_lib.DATA_PLANE_STATUS):
104 + port_res[dps_lib.DATA_PLANE_STATUS] = (
105 + port_db[dps_lib.DATA_PLANE_STATUS].data_plane_status)
106 diff --git a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
107 index 1c625bc83..8c1796ba3 100644
108 --- a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
109 +++ b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
113 diff --git a/neutron/db/migration/alembic_migrations/versions/pike/expand/804a3c76314c_add_data_plane_status_to_port.py b/neutron/db/migration/alembic_migrations/versions/pike/expand/804a3c76314c_add_data_plane_status_to_port.py
115 index 000000000..bd4d1472b
117 +++ b/neutron/db/migration/alembic_migrations/versions/pike/expand/804a3c76314c_add_data_plane_status_to_port.py
119 +# Copyright 2017 OpenStack Foundation
121 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
122 +# not use this file except in compliance with the License. You may obtain
123 +# a copy of the License at
125 +# http://www.apache.org/licenses/LICENSE-2.0
127 +# Unless required by applicable law or agreed to in writing, software
128 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
129 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
130 +# License for the specific language governing permissions and limitations
131 +# under the License.
134 +"""Add data_plane_status to Port
136 +Revision ID: 804a3c76314c
137 +Revises: a9c43481023c
138 +Create Date: 2017-01-17 13:51:45.737987
142 +# revision identifiers, used by Alembic.
143 +revision = '804a3c76314c'
144 +down_revision = 'a9c43481023c'
146 +from alembic import op
147 +import sqlalchemy as sa
151 + op.create_table('portdataplanestatuses',
152 + sa.Column('port_id', sa.String(36),
153 + sa.ForeignKey('ports.id',
154 + ondelete="CASCADE"),
155 + primary_key=True, index=True),
156 + sa.Column('data_plane_status', sa.String(length=16),
158 diff --git a/neutron/db/models/data_plane_status.py b/neutron/db/models/data_plane_status.py
160 index 000000000..ada10af55
162 +++ b/neutron/db/models/data_plane_status.py
164 +# Copyright (c) 2017 NEC Corporation. All rights reserved.
166 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
167 +# not use this file except in compliance with the License. You may obtain
168 +# a copy of the License at
170 +# http://www.apache.org/licenses/LICENSE-2.0
172 +# Unless required by applicable law or agreed to in writing, software
173 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
174 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
175 +# License for the specific language governing permissions and limitations
176 +# under the License.
178 +from neutron_lib.db import model_base
179 +import sqlalchemy as sa
180 +from sqlalchemy import orm
182 +from neutron.db import models_v2
185 +class PortDataPlaneStatus(model_base.BASEV2):
186 + __tablename__ = 'portdataplanestatuses'
188 + port_id = sa.Column(sa.String(36),
189 + sa.ForeignKey('ports.id', ondelete="CASCADE"),
190 + primary_key=True, index=True)
191 + data_plane_status = sa.Column(sa.String(16), nullable=True)
192 + port = orm.relationship(
193 + models_v2.Port, load_on_pending=True,
194 + backref=orm.backref("data_plane_status",
195 + lazy='joined', uselist=False,
197 + revises_on_change = ('port', )
198 diff --git a/neutron/extensions/data_plane_status.py b/neutron/extensions/data_plane_status.py
200 index 000000000..8e225e670
202 +++ b/neutron/extensions/data_plane_status.py
204 +# Copyright (c) 2017 NEC Corporation. All rights reserved.
206 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
207 +# not use this file except in compliance with the License. You may obtain
208 +# a copy of the License at
210 +# http://www.apache.org/licenses/LICENSE-2.0
212 +# Unless required by applicable law or agreed to in writing, software
213 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
214 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
215 +# License for the specific language governing permissions and limitations
216 +# under the License.
218 +from neutron_lib.api.definitions import data_plane_status
219 +from neutron_lib.api import extensions
222 +class Data_plane_status(extensions.ExtensionDescriptor):
226 + return data_plane_status.NAME
229 + def get_alias(cls):
230 + return data_plane_status.ALIAS
233 + def get_description(cls):
234 + return data_plane_status.DESCRIPTION
237 + def get_updated(cls):
238 + return data_plane_status.UPDATED_TIMESTAMP
240 + def get_required_extensions(self):
241 + return data_plane_status.REQUIRED_EXTENSIONS or []
243 + def get_optional_extensions(self):
244 + return data_plane_status.OPTIONAL_EXTENSIONS or []
246 + def get_extended_resources(self, version):
247 + if version == "2.0":
248 + return data_plane_status.RESOURCE_ATTRIBUTE_MAP
251 diff --git a/neutron/objects/port/extensions/data_plane_status.py b/neutron/objects/port/extensions/data_plane_status.py
253 index 000000000..bd5858123
255 +++ b/neutron/objects/port/extensions/data_plane_status.py
257 +# Copyright (c) 2017 NEC Corporation. All rights reserved.
259 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
260 +# not use this file except in compliance with the License. You may obtain
261 +# a copy of the License at
263 +# http://www.apache.org/licenses/LICENSE-2.0
265 +# Unless required by applicable law or agreed to in writing, software
266 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
267 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
268 +# License for the specific language governing permissions and limitations
269 +# under the License.
271 +from oslo_versionedobjects import base as obj_base
272 +from oslo_versionedobjects import fields as obj_fields
274 +from neutron.db.models import data_plane_status as db_models
275 +from neutron.objects import base
276 +from neutron.objects import common_types
279 +@obj_base.VersionedObjectRegistry.register
280 +class PortDataPlaneStatus(base.NeutronDbObject):
281 + # Version 1.0: Initial version
284 + db_model = db_models.PortDataPlaneStatus
286 + primary_keys = ['port_id']
289 + 'port_id': common_types.UUIDField(),
290 + 'data_plane_status': obj_fields.StringField(),
293 + foreign_keys = {'Port': {'port_id': 'id'}}
294 diff --git a/neutron/objects/ports.py b/neutron/objects/ports.py
295 index bbddb4dde..dd83db147 100644
296 --- a/neutron/objects/ports.py
297 +++ b/neutron/objects/ports.py
302 +from oslo_utils import versionutils
303 from oslo_versionedobjects import base as obj_base
304 from oslo_versionedobjects import fields as obj_fields
306 @@ -206,7 +207,8 @@ class PortDNS(base.NeutronDbObject):
307 @obj_base.VersionedObjectRegistry.register
308 class Port(base.NeutronDbObject):
309 # Version 1.0: Initial version
311 + # Version 1.1: Add data_plane_status field
314 db_model = models_v2.Port
316 @@ -227,6 +229,9 @@ class Port(base.NeutronDbObject):
317 'binding': obj_fields.ObjectField(
318 'PortBinding', nullable=True
320 + 'data_plane_status': obj_fields.ObjectField(
321 + 'PortDataPlaneStatus', nullable=True
323 'dhcp_options': obj_fields.ListOfObjectsField(
324 'ExtraDhcpOpt', nullable=True
326 @@ -260,6 +265,7 @@ class Port(base.NeutronDbObject):
327 'allowed_address_pairs',
330 + 'data_plane_status',
332 'distributed_binding',
334 @@ -374,3 +380,9 @@ class Port(base.NeutronDbObject):
336 self.qos_policy_id = None
337 self.obj_reset_changes(['qos_policy_id'])
339 + def obj_make_compatible(self, primitive, target_version):
340 + _target_version = versionutils.convert_version_to_tuple(target_version)
342 + if _target_version < (1, 1):
343 + primitive.pop('data_plane_status')
344 diff --git a/neutron/plugins/ml2/extensions/data_plane_status.py b/neutron/plugins/ml2/extensions/data_plane_status.py
346 index 000000000..850dafab6
348 +++ b/neutron/plugins/ml2/extensions/data_plane_status.py
350 +# Copyright (c) 2017 NEC Corporation. All rights reserved.
352 +# Licensed under the Apache License, Version 2.0 (the "License"); you may
353 +# not use this file except in compliance with the License. You may obtain
354 +# a copy of the License at
356 +# http://www.apache.org/licenses/LICENSE-2.0
358 +# Unless required by applicable law or agreed to in writing, software
359 +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
360 +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
361 +# License for the specific language governing permissions and limitations
362 +# under the License.
364 +from neutron_lib.api.definitions import data_plane_status as dps_lib
365 +from oslo_log import log as logging
367 +from neutron.db import data_plane_status_db as dps_db
368 +from neutron.plugins.ml2 import driver_api as api
370 +LOG = logging.getLogger(__name__)
373 +class DataPlaneStatusExtensionDriver(api.ExtensionDriver,
374 + dps_db.DataPlaneStatusMixin):
375 + _supported_extension_alias = 'data-plane-status'
377 + def initialize(self):
378 + LOG.info("DataPlaneStatusExtensionDriver initialization complete")
381 + def extension_alias(self):
382 + return self._supported_extension_alias
384 + def process_update_port(self, plugin_context, data, result):
385 + if dps_lib.DATA_PLANE_STATUS in data:
386 + self._process_update_port_data_plane_status(plugin_context,
389 + def extend_port_dict(self, session, db_data, result):
390 + self._extend_port_data_plane_status(result, db_data)