Merge "Fix URL anchor in apex document."
[apex.git] / build / patches / neutron_server_dps.patch
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
5
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.
9
10 Supported statuses:
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
14
15 Setting attribute available to admin or any user with specific role
16 (default role: data_plane_integrator).
17
18 ML2 extension driver loaded on request via configuration:
19
20   [ml2]
21   extension_drivers = data_plane_status
22
23 Related-Bug: #1598081
24 Related-Bug: #1575146
25
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
30
31 Implements: blueprint port-data-plane-status
32
33 Depends-On: I04eef902b3310f799b1ce7ea44ed7cf77c74da04
34 Change-Id: Ic9e1e3ed9e3d4b88a4292114f4cb4192ac4b3502
35 ---
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
51
52 diff --git a/neutron/db/data_plane_status_db.py b/neutron/db/data_plane_status_db.py
53 new file mode 100644
54 index 000000000..4e5c23aef
55 --- /dev/null
56 +++ b/neutron/db/data_plane_status_db.py
57 @@ -0,0 +1,48 @@
58 +# Copyright (c) 2017 NEC Corporation.  All rights reserved.
59 +#
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
63 +#
64 +#         http://www.apache.org/licenses/LICENSE-2.0
65 +#
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
70 +#    under the License.
71 +
72 +from neutron_lib.api.definitions import data_plane_status as dps_lib
73 +
74 +from neutron.objects.port.extensions import data_plane_status as dps_obj
75 +
76 +
77 +class DataPlaneStatusMixin(object):
78 +    """Mixin class to add data plane status to a port"""
79 +
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])
83 +        obj.create()
84 +        res[dps_lib.DATA_PLANE_STATUS] = data[dps_lib.DATA_PLANE_STATUS]
85 +
86 +    def _process_update_port_data_plane_status(self, context, data,
87 +                                               res):
88 +        if dps_lib.DATA_PLANE_STATUS not in data:
89 +            return
90 +
91 +        obj = dps_obj.PortDataPlaneStatus.get_object(context,
92 +                                                     port_id=res['id'])
93 +        if obj:
94 +            obj.data_plane_status = data[dps_lib.DATA_PLANE_STATUS]
95 +            obj.update()
96 +            res[dps_lib.DATA_PLANE_STATUS] = data[dps_lib.DATA_PLANE_STATUS]
97 +        else:
98 +            self._process_create_port_data_plane_status(context, data, res)
99 +
100 +    def _extend_port_data_plane_status(self, port_res, port_db):
101 +        port_res[dps_lib.DATA_PLANE_STATUS] = None
102 +
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
110 @@ -1 +1 @@
111 -a9c43481023c
112 +804a3c76314c
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
114 new file mode 100644
115 index 000000000..bd4d1472b
116 --- /dev/null
117 +++ b/neutron/db/migration/alembic_migrations/versions/pike/expand/804a3c76314c_add_data_plane_status_to_port.py
118 @@ -0,0 +1,39 @@
119 +# Copyright 2017 OpenStack Foundation
120 +#
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
124 +#
125 +#         http://www.apache.org/licenses/LICENSE-2.0
126 +#
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.
132 +#
133 +
134 +"""Add data_plane_status to Port
135 +
136 +Revision ID: 804a3c76314c
137 +Revises: a9c43481023c
138 +Create Date: 2017-01-17 13:51:45.737987
139 +
140 +"""
141 +
142 +# revision identifiers, used by Alembic.
143 +revision = '804a3c76314c'
144 +down_revision = 'a9c43481023c'
145 +
146 +from alembic import op
147 +import sqlalchemy as sa
148 +
149 +
150 +def upgrade():
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),
157 +                              nullable=True))
158 diff --git a/neutron/db/models/data_plane_status.py b/neutron/db/models/data_plane_status.py
159 new file mode 100644
160 index 000000000..ada10af55
161 --- /dev/null
162 +++ b/neutron/db/models/data_plane_status.py
163 @@ -0,0 +1,34 @@
164 +# Copyright (c) 2017 NEC Corporation.  All rights reserved.
165 +#
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
169 +#
170 +#         http://www.apache.org/licenses/LICENSE-2.0
171 +#
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.
177 +
178 +from neutron_lib.db import model_base
179 +import sqlalchemy as sa
180 +from sqlalchemy import orm
181 +
182 +from neutron.db import models_v2
183 +
184 +
185 +class PortDataPlaneStatus(model_base.BASEV2):
186 +    __tablename__ = 'portdataplanestatuses'
187 +
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,
196 +                            cascade='delete'))
197 +    revises_on_change = ('port', )
198 diff --git a/neutron/extensions/data_plane_status.py b/neutron/extensions/data_plane_status.py
199 new file mode 100644
200 index 000000000..8e225e670
201 --- /dev/null
202 +++ b/neutron/extensions/data_plane_status.py
203 @@ -0,0 +1,47 @@
204 +# Copyright (c) 2017 NEC Corporation.  All rights reserved.
205 +#
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
209 +#
210 +#         http://www.apache.org/licenses/LICENSE-2.0
211 +#
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.
217 +
218 +from neutron_lib.api.definitions import data_plane_status
219 +from neutron_lib.api import extensions
220 +
221 +
222 +class Data_plane_status(extensions.ExtensionDescriptor):
223 +
224 +    @classmethod
225 +    def get_name(cls):
226 +        return data_plane_status.NAME
227 +
228 +    @classmethod
229 +    def get_alias(cls):
230 +        return data_plane_status.ALIAS
231 +
232 +    @classmethod
233 +    def get_description(cls):
234 +        return data_plane_status.DESCRIPTION
235 +
236 +    @classmethod
237 +    def get_updated(cls):
238 +        return data_plane_status.UPDATED_TIMESTAMP
239 +
240 +    def get_required_extensions(self):
241 +        return data_plane_status.REQUIRED_EXTENSIONS or []
242 +
243 +    def get_optional_extensions(self):
244 +        return data_plane_status.OPTIONAL_EXTENSIONS or []
245 +
246 +    def get_extended_resources(self, version):
247 +        if version == "2.0":
248 +            return data_plane_status.RESOURCE_ATTRIBUTE_MAP
249 +        else:
250 +            return {}
251 diff --git a/neutron/objects/port/extensions/data_plane_status.py b/neutron/objects/port/extensions/data_plane_status.py
252 new file mode 100644
253 index 000000000..bd5858123
254 --- /dev/null
255 +++ b/neutron/objects/port/extensions/data_plane_status.py
256 @@ -0,0 +1,37 @@
257 +# Copyright (c) 2017 NEC Corporation.  All rights reserved.
258 +#
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
262 +#
263 +#         http://www.apache.org/licenses/LICENSE-2.0
264 +#
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.
270 +
271 +from oslo_versionedobjects import base as obj_base
272 +from oslo_versionedobjects import fields as obj_fields
273 +
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
277 +
278 +
279 +@obj_base.VersionedObjectRegistry.register
280 +class PortDataPlaneStatus(base.NeutronDbObject):
281 +    # Version 1.0: Initial version
282 +    VERSION = "1.0"
283 +
284 +    db_model = db_models.PortDataPlaneStatus
285 +
286 +    primary_keys = ['port_id']
287 +
288 +    fields = {
289 +        'port_id': common_types.UUIDField(),
290 +        'data_plane_status': obj_fields.StringField(),
291 +    }
292 +
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
298 @@ -13,6 +13,7 @@
299  #    under the License.
300  
301  import netaddr
302 +from oslo_utils import versionutils
303  from oslo_versionedobjects import base as obj_base
304  from oslo_versionedobjects import fields as obj_fields
305  
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
310 -    VERSION = '1.0'
311 +    # Version 1.1: Add data_plane_status field
312 +    VERSION = '1.1'
313  
314      db_model = models_v2.Port
315  
316 @@ -227,6 +229,9 @@ class Port(base.NeutronDbObject):
317          'binding': obj_fields.ObjectField(
318              'PortBinding', nullable=True
319          ),
320 +        'data_plane_status': obj_fields.ObjectField(
321 +            'PortDataPlaneStatus', nullable=True
322 +        ),
323          'dhcp_options': obj_fields.ListOfObjectsField(
324              'ExtraDhcpOpt', nullable=True
325          ),
326 @@ -260,6 +265,7 @@ class Port(base.NeutronDbObject):
327          'allowed_address_pairs',
328          'binding',
329          'binding_levels',
330 +        'data_plane_status',
331          'dhcp_options',
332          'distributed_binding',
333          'dns',
334 @@ -374,3 +380,9 @@ class Port(base.NeutronDbObject):
335          else:
336              self.qos_policy_id = None
337          self.obj_reset_changes(['qos_policy_id'])
338 +
339 +    def obj_make_compatible(self, primitive, target_version):
340 +        _target_version = versionutils.convert_version_to_tuple(target_version)
341 +
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
345 new file mode 100644
346 index 000000000..850dafab6
347 --- /dev/null
348 +++ b/neutron/plugins/ml2/extensions/data_plane_status.py
349 @@ -0,0 +1,41 @@
350 +# Copyright (c) 2017 NEC Corporation.  All rights reserved.
351 +#
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
355 +#
356 +#         http://www.apache.org/licenses/LICENSE-2.0
357 +#
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.
363 +
364 +from neutron_lib.api.definitions import data_plane_status as dps_lib
365 +from oslo_log import log as logging
366 +
367 +from neutron.db import data_plane_status_db as dps_db
368 +from neutron.plugins.ml2 import driver_api as api
369 +
370 +LOG = logging.getLogger(__name__)
371 +
372 +
373 +class DataPlaneStatusExtensionDriver(api.ExtensionDriver,
374 +                                     dps_db.DataPlaneStatusMixin):
375 +    _supported_extension_alias = 'data-plane-status'
376 +
377 +    def initialize(self):
378 +        LOG.info("DataPlaneStatusExtensionDriver initialization complete")
379 +
380 +    @property
381 +    def extension_alias(self):
382 +        return self._supported_extension_alias
383 +
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,
387 +                                                        data, result)
388 +
389 +    def extend_port_dict(self, session, db_data, result):
390 +        self._extend_port_data_plane_status(result, db_data)
391 -- 
392 2.12.3
393