28a495eb6caf469da6ff58c705d9c4dd1f29b84e
[docs.git] / docs / release-notes / upgrade-process.rst
1 ===================================
2 2021.09 Phosphorus Platform Upgrade
3 ===================================
4
5 This document describes the steps to help users upgrade from Silicon
6 to Phosphorus planned platform. Refer to `Managed Release Integrated (MRI)
7 project <https://git.opendaylight.org/gerrit/q/topic:phosphorus-mri>`_
8 upgrade patches for more information.
9
10 .. contents:: Contents
11
12 Preparation
13 -----------
14
15 JDK 11 Version
16 ^^^^^^^^^^^^^^
17 Phosphorus requires Java 11, both during compile-time and run-time.
18 Make sure to install JDK 11 corresponding to at least ``openjdk-11.0.10``,
19 and that the JAVA_HOME environment variable points to the JDK directory.
20
21 Version Bump
22 ^^^^^^^^^^^^
23 Before performing platform upgrade, do the following to bump the odlparent
24 versions (for example, `bump-odl-version <https://github.com/skitt/odl-tools/blob/master/bump-odl-version>`_):
25
26 1. Update the odlparent version from 8.1.1 to 9.0.5. There should
27    not be any reference to **org.opendaylight.odlparent**, except
28    for 9.0.5. This includes custom feature.xml templates
29    (``src/main/feature/feature.xml``), the version range should
30    be "[9,10)" instead of "[8.1,9)", "[5.0.3,6)" or any other variation.
31
32  .. code-block:: shell
33
34   bump-odl-version odlparent 8.1.1 9.0.5
35
36 2. Update the direct yangtools version references from 6.0.5 to 7.0.7,
37    There should not be any reference to **org.opendaylight.yangtools**,
38    except for 7.0.7. This includes custom feature.xml templates
39    (``src/main/feature/feature.xml``), the version range should
40    be "[7,8)" instead of "[6,7)".
41
42  .. code-block:: shell
43
44   bump-odl-version yangtools 6.0.5 7.0.7
45
46 3. Update the MD-SAL version from 7.0.6 to 8.0.5. There should not be
47    any reference to **org.opendaylight.mdsal**, except for 8.0.5.
48
49  .. code-block:: shell
50
51   bump-odl-version mdsal 7.0.6 8.0.5
52
53 4. Update the Controller version from 3.0.7 to 4.0.2. There should not be
54    any reference to **org.opendaylight.controller**, except for 4.0.2.
55
56  .. code-block:: shell
57
58   bump-odl-version controller 3.0.7 4.0.2
59
60 5. Update the InfraUtils version from 1.9.6 to 2.0.5. There should not be
61    any reference to **org.opendaylight.infrautils**, except for 2.0.5.
62
63  .. code-block:: shell
64
65   bump-odl-version infrautils 1.9.6 2.0.5
66
67 6. Update the AAA version from 1.13.0 to 0.14.2. There should not be
68    any reference to **org.opendaylight.aaa**, except for 0.14.2.
69
70  .. code-block:: shell
71
72   bump-odl-version aaa 0.13.2 0.14.2
73
74 7. Update the NETCONF version from 1.13.1 to 2.0.5. There should not be
75    any reference to **org.opendaylight.netconf**, except for 2.0.5.
76
77  .. code-block:: shell
78
79   bump-odl-version netconf 1.13.1 2.0.5
80
81 Install Dependent Projects
82 ^^^^^^^^^^^^^^^^^^^^^^^^^^
83 Before performing platform upgrade, users must also install
84 any dependent project. To locally install a dependent project,
85 pull and install the respective
86 `phosphorus-mri <https://git.opendaylight.org/gerrit/q/topic:phosphorus-mri>`_
87 changes for any dependent project.
88
89 Perform the following steps to save time when locally installing
90 any dependent project:
91
92 * For quick install:
93
94  .. code-block:: shell
95
96   mvn -Pq clean install
97
98 * If previously installed, go offline and/or use the
99   no-snapshot-update option.
100
101  .. code-block:: shell
102
103   mvn -Pq -o -nsu clean install
104
105 Upgrade the ODL Parent
106 ----------------------
107 The following sub-section describes how to upgrade to
108 the ODL Parent version 9. Refer to the `ODL Parent Release Notes
109 <https://github.com/opendaylight/odlparent/blob/master/docs/NEWS.rst#version-902>`_
110 for more information.
111
112 Features
113 ^^^^^^^^
114 Any version range referencing version 8 or 8.1 of ODL Parent must be changed
115 to “[9,10)” for ODL Parent 9.
116
117  .. code-block:: xml
118
119    <feature name="odl-infrautils-caches">
120        <feature version="[9,10)">odl-guava</feature>
121    </feature>
122
123 ODL Parent Impacts
124 ------------------
125
126 Updated JSR-330 coordinates
127 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
128 ODL Parent has switched to sourcing ``javax.inject`` artifact from the GuicedEE project in version 8.1.
129 With odlparent-9, the old coordinates were removed. Downstreams need to update their dependency blocks to:
130
131  .. code-block:: xml
132
133    <dependency>
134        <groupId>com.guicedee.services</groupId>
135        <artifactId>javax.inject</artifactId>
136        <optional>true</optional>
137    </dependency>
138
139
140 Removed OSGi Release 6 `osgi-core`
141 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
142 The artifact name for OSGi Core specification has changed in Release 7. Where odlparent-8.1 provided both R6 and R7
143 declarations, odlparent-9 removes the legacy declaration. Downstreams need to update their dependency blocks to:
144
145  .. code-block:: xml
146
147    <dependency>
148        <groupId>org.osgi</groupId>
149        <artifactId>osgi.core</artifactId>
150    </dependency>
151
152
153 YANG Tools Impacts
154 ------------------
155
156 SchemaNode.getPath() can throw UnsupportedOperationException
157 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
158 The original idea that each SchemaNode has a unique identifier, available through ``SchemaNode.getPath()``,
159 has proven to be a scalability issue with vendor models. The identifiers themselves account for up to 19%
160 of all objects retained by EffectiveModelContext, holding up to 17% of retained memory. These are also
161 preventing a number of useful performance and memory footprint optimizations.
162
163 In yangtools-6 we set out on eliminating this problem, with TypeDefinition's `getPath()` method being
164 specified as being optional -- but the implementation supported this method.
165
166 In yangtools-7 we are taking next three steps:
167   * we make `SchemaNode.getPath()` an default method, with the default implementation throwing
168     UnsupportedOperationException
169   * we are changing TypeDefinition implementation to actually throw UnsupportedOperationException
170     in all cases
171   * we are making `SchemaNode.getPath()` deprecated for removal
172
173 All other types of SchemaNode except TypeDefinition retain a fully functional `getPath()` as an implementation
174 detail, providing seamless interoperation with current code in most cases.
175
176
177 NormalizedNode hierarchy was updated
178 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
179 The interfaces representing normalized view of YANG-modeled data, rooted at
180 ``org.opendaylight.yangtools.yang.data.api.NormalizedNode``, have been revamped for easier use and better
181 consistency of operations.
182
183 The most prolific change is the reduction of number of generic arguments for ``NormalizedNode``, ``DataContainerChild``
184 and ``NormalizedNodeContainer``. The first two now do not have any generic arguments, while NormalizedNodeContainer
185 has only a single argument.
186
187 This prompts a very simple replacement pattern, where uses like this:
188
189  .. code-block:: java
190
191    NormalizedNode<?, ?> node = ...
192    NormalizedNodeContainer<?, ?, ?> parent = ...
193    DataContainerChild<?, ?> child = ...
194
195 are simplified down to
196
197  .. code-block:: java
198
199    NormalizedNode node = ...
200    NormalizedNodeContainer<?> parent = ...
201    DataContainerChild child = ...
202
203
204 Base NormalizedNode interface has also been changed. The ``NormalizedNode.getNodeType()`` method has been removed,
205 as it does not work well with ``AugmentationIdentifier`` -- leaving only three methods:
206
207   * ``getIdentifier()`` inherited from the ``Identifiable`` contract
208   * ``body()``, which is actually the new name for ``value()``
209   * ``contract()``, which identifies which NormalizedNode specialization, such as ContainerNode or AnydataNode,
210     a particular object represents
211
212 For most users, this change simply means replacing code blocks like
213
214  .. code-block:: java
215
216    NormalizedNode<?, ?> node;
217    QName type = node.getNodeType();
218    Object value = node.getValue();
219
220 with a slightly more verbose
221
222  .. code-block:: java
223
224    NormalizedNode node;
225    QName type = node.getIdentifier().getNodeType();
226    Object value = node.body();
227
228 which makes safety of `getNodeType()` obvious as soon as NormalizedNode subtypes (such as ContainerNode, MapNode) are
229 actually involved.
230
231 Also NormalizedNodeContainer's function has changed. It now correctly acts as a common interface
232 between containers which allow key-based child look-up (``DistinctNodeContainer``) and containers which allow
233 offset-based child look-up (``OrderedNodeContainer``), hosting utility methods like ``size()`` and ``isEmpty()``.
234 Call sites which iterate through all available children should continue using NormalizedNodeContainer. Call sites
235 which require accessing a child by its identifier need to switch to using DistinctNodeContainer:
236
237  .. code-block:: java
238
239    NormalizedNodeContainer<?, ?, ?> container;
240    PathArgument arg;
241    DataContainerChild<?, ?> child = container.getDataChildByName(arg);
242
243 ends up being migrated to
244
245  .. code-block:: java
246
247    DistinctNodeContainer<?> container;
248    PathArgument arg;
249    DataContainerChild child = container.childByArg(arg);
250
251 There actually are now three different methods to access a child, allowing flexible and expressive integration:
252   * ``childByArg()``, which returns a child or ``null``,
253   * ``findChildByArg()``, which returns a ``Optional`` child,
254   * ``getChildByArg()``, which returns a child or throws VerifyException
255
256
257 Another aspect that got attention is child ordering contract. Both ``MapNode`` and ``LeafSetNode`` are now
258 specialized in disjunct interfaces based on how child iteration order affects semantics. ``SystemMapNode`` and
259 ``SystemLeafSetNode`` represent ``list`` and ``leaf-list`` constructs which have ``ordered-by system`` semantics --
260 which is to say order of nodes is not part of semantics similar to what ``java.util.Set`` does. On the other hand
261 we have ``UserMapNode`` and ``UserLeafSetNode`` for constructs which are ``ordered-by user`` -- hence the child
262 iteration order is part of semantics, i.e. what ``java.util.List`` does.
263
264
265 ModelStatement non-existent arguments
266 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
267 The type mapping of YANG statements argument in the no-argument case has changed. These have been previously mapped
268 to ``java.lang.Void`` to express non-presence. This mapping has caused nullability issues of ``ModelStatement.argument()``.
269 These have been resolved through mapping non-existent arguments to ``org.opendaylight.yangtools.yang.common.Empty``,
270 which maintains the same 'nothingness' contract through a singleton non-null object.
271
272
273 XML namespace has a dedicated construct
274 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
275 In previous versions, we have used ``java.net.URI`` to model the argument of YANG ``namespace`` statement. This has
276 proven to be a bit inefficient from both memory and CPU perspective, for example during looks. In this version, YANG
277 namespace is represented by a dedicated ``org.opendaylight.yangtools.yang.common.XMLNamespace`` class. It performs
278 same validation as ``URI.create()`` does, but it does not break the string into its constituents for storage like URI
279 does.
280
281
282 DataSchemaNode's `isConfigration()` is three-state
283 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
284 The idea that a DataSchemaNode has a boolean attribute representing the effective value of ``config`` statement argument
285 has been problematic due to its ignoring definition scope. As an example, ``leaf`` defined in a ``grouping`` has neither
286 ``config true`` nor ``config false`` effective statement.
287
288 In order to fix this modeling problem, as well to stop users from attempting to perform various recovery strategies,
289 a new method, ``DataSchemaNode.effectiveConfig()``, has been introduced. This method returns ``Optional<Boolean>``,
290 accurately modeling the three possibilities. ``DataSchemaNode.isConfiguration()`` has also been deprecated for removal.
291
292
293 SchemaContextUtil has been removed
294 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
295 A number of utilities dealing with SchemaNode traversal have been hosted in SchemaContextUtil. All of these were created
296 with assumptions of ``SchemaPath`` and with the object model not understanding YANG XPath expressions. This has lead to
297 some very obscure code with problematic edge cases.
298
299 All of these utilities have been centralized in a stateful SchemaInferenceStack. This stack encapsulates state related to
300 how a piece of logic has come to know about an EffectiveStatement. There are number of simple operations, such as
301 ``enterDataTree(QName)``, ``enterGrouping(QName)``, ``exit()`` and similar.
302
303 The stack also provides faculties to resolve ``type leafref`` path expressions, adjusting its internal state to provide
304 a path from the conceptual schema root to the leaf a particular leafref (indirectly) points to.
305
306 State of a SchemaInferenceStack can be converted to an immutable ``EffectiveStatementInference`` instance. This construct
307 serves as the modern replacement of ``SchemaPath``. Rather than containing an opaque path, though, it contains a sequence
308 of statements and attached semantics. This allows us to accurately address statements and communicate the state of the
309 SchemaInferenceStack across API boundaries, as a SchemaInferenceStack can readily be reconstituted from a number of different
310 EffectiveStatementInferences.
311
312 A number of entry-points, most notably to XML and JSON codecs, now take an ``EffectiveStatementInference`` instead of
313 a ``SchemaPath`` or a context ``SchemaNode``. For migration purposes, users having these available can use the following
314 snippet to migrate:
315
316  .. code-block:: java
317
318    EffectiveModelContext context = ...;
319    SchemaNode node = ...;
320    EffectiveStatementInference inference = SchemaInferenceStack.ofSchemaPath(context, node.getPath()).toInference();
321
322
323 Strictly-compliant `leafref` path interpretation
324 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
325 Previous versions of YANG Tools have had a number of ways how to resolve where a ``leafref``'s ``path`` statement is
326 pointing to. Each of these operated on a different set of assumptions and had its share of caveats and outright bugs --
327 most of them stemming from their attempt to operate on raw strings as declared in YANG files.
328
329 All of these utilities have been removed in this release and superseded by a single implementation in aforementioned
330 ``SchemaInferenceStack``. This implementation maintains an
331 `XPath Context <https://datatracker.ietf.org/doc/html/rfc7950#section-6.4.1>`__ and performs unqualified name resolution
332 based upon its rules.
333
334 Low-level API is ``SchemaInferenceStack.resolvePathExpression()``, which takes a ``PathExpression`` and interprets it
335 in the context of its current state. On successful return the statement which the expression points will be return and
336 the stack will be updated to be at that statement.
337
338 High-level API is captured in ``LeafrefResolver`` API, allowing users to (recursively) resolve the actual type that a
339 particular ``LeafrefTypeDefinition`` points to. SchemaInferenceStack is its canonical implementation.
340
341 End-user visible behavior has changed in that incorrect leafref paths are now readily identified. This typically affects
342 cross-module use of ``type leafref`` with absolute paths in either ``typedef`` or in ``grouping`` contexts. Typical source
343 of trouble looks like this:
344
345  .. code-block:: yang
346
347   module foo {
348     prefix foo;
349
350     typedef foo-ref {
351       type leafref {
352         path /foo;
353       }
354     }
355
356     leaf foo {
357       type string;
358     }
359   }
360
361   module bar {
362     prefix bar;
363
364     import foo {
365       prefix foo;
366     }
367
368     leaf bar {
369       type foo:foo-ref;
370     }
371   }
372
373 Note how ``foo-ref`` is using an absolute path with unqualified name. The intent seems to be to point at the ``foo:foo``
374 leaf and in fact all uses within ``foo`` module operate as expected. In the context of ``bar`` module, though, things
375 break down. When we are looking at ``bar:bar`` leaf, the path becomes ``/bar:foo`` -- and thus attempts to resolve it
376 will fail. Correct fix in this situation is to correct the definition of the path to use qualified names:
377
378  .. code-block:: yang
379
380   typedef foo-ref {
381     type leafref {
382       path /foo:foo;
383     }
384   }
385
386
387 Unrecognized YANG statement handling
388 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
389 YANG parser does not reflect unrecognized YANG language extensions, defined by
390 an ``extension`` statement, in the effective model as exposed by EffectiveModelContext.
391
392 This has a direct impact on the contents of ``DocumentedNode.getUnknownSchemaNodes()``, as unrecognized extensions
393 will not be presented in the list.
394
395 Unrecognized extensions are those that are defined by an ``extension`` statement, but do not have a corresponding
396 YANG parser handler. These extensions cannot be semantically be bound and the YANG parser handles in accordance with
397 `RFC6020 <https://datatracker.ietf.org/doc/html/rfc6020#section-6.3.1>`__ by treating them as unsupported extensions
398 and ignoring them.
399
400
401 MD-SAL Impacts
402 --------------
403 This MD-SAL release contains a completely rewritten Java Binding generator.
404
405 The implementation now performs a multi-pass generation as opposed to a memorized single-pass generation approach
406 taken by the previous implementation. Multiple passes allow for proper name allocation policies, with conflicts
407 being resolved in a consistent matter-of-course way.
408
409 Forward compatibility with Java 16
410 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
411 Java has reserved a few new keywords, ``var``, ``yield`` and most notably ``record``. These are now taken into
412 account when generating Java bindings, resulting in slightly different package names being generated, as they are
413 now prefixed with a single underscore.
414
415 For example ``org.opendaylight.yang.gen.v1.foo.record.bar`` is now generated as
416 ``org.opendaylight.yang.gen.v1.foo._record.bar``.
417
418
419 Augmentation child package names
420 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
421 As part of class/package name mapping rules, augmentation class name overrides also apply to package names. For
422 this example YANG
423
424  .. code-block:: yang
425
426    import yang-ext {
427      prefix ext;
428    }
429
430    container foo {
431      container bar;
432    }
433
434    augment /foo/bar {
435      ext:augment-identifier baz;
436
437      container xyzzy;
438    }
439
440
441 we would generate ``foo.bar.Xyzzy`` interface. Since the augmentation now makes a proper claim on the ``baz``
442 name, we generate ``baz.Xyzzy`` instead.
443
444 This change also mean that attempts to define multiple augments with the same augment-identifier will result
445 in a build failure.
446
447
448 RPCs now reserve the corresponding class name
449 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
450 Binding mapping of ``action`` and ``rpc`` statements are slightly different, reflecting the evolution of Java
451 as well as our assembly of features. In the long term we want to evolve ``rpc`` mapping to resemble more the
452 way ``action`` is mapped. As a preparatory step, ``rpc`` statements now reserve the class (and package) names
453 corresponding to the RPC argument. This does not affect most use cases, but slightly changes interactions with
454 groupings on naming overlap. For the following fragment
455
456  .. code-block:: yang
457
458    module foo {
459      grouping foo;
460      rpc foo;
461    }
462
463 we used to generate ``FooService``, ``FooInput`` and ``FooOutput`` for the RPC and ``Foo`` for the grouping. In
464 this release we generate ``Foo$G`` for the grouping, leaving ``Foo`` non-existent. A future version will take
465 advantage of this gap and generate an interface for the RPC.
466
467
468 DOMDataTreeChangeListener.onInitialData() is mandatory
469 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
470 DOMDataTreeChangeListener's callback for initially-empty data, ``onInitialData()``, is no longer a default
471 method and therefore is mandatory to implement. It is okay for this method to do nothing, but some users may
472 choose to perform some processing, similar to what they'd do if the listen root were to be deleted.
473
474
475 Widened Integer/Long/BigInteger compatibility setters and constructors removed
476 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
477 In releases prior to Magnesium ``uint8``, ``uint16``, ``uint32`` and ``uint64`` types were mapped to Short, Integer,
478 Long and BigInteger respectively. With Magnesium, this mapping changed to ``yang.common.Uint{8,16,32,64}`` and
479 compatibility ``setFoo(Short)`` methods were retained as adapters to minimize the API churn.
480
481 In this release these compatibility methods are no longer generated, as detailed in
482 `this MD-SAL issue <https://jira.opendaylight.org/browse/MDSAL-490>`__.
483
484
485 List/Map compatibility setters and constructors removed
486 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
487 In releases prior to Aluminium, ``list`` statements were always mapped to ``java.util.List``. With Aluminium, this
488 mapping was updated to take into account the semantic meaning implied by ``ordered-by`` statements. For ``list``
489 statements, which are ``ordered-by system`` and also have a ``key`` statement, the mapping was changed to
490 ``java.util.Map``. Compatibility constructors and setters were retained as adapters to minimize the API churn.
491
492 In this release these compatibility methods are no longer generated, as detailed in
493 `this MD-SAL issue <https://jira.opendaylight.org/browse/MDSAL-540>`__.
494
495
496 Boolean compatibility getters removed
497 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
498 In releases prior to Silicon, ``type boolean`` getters were mapped to ``is`` prefix instead of the regular ``get``
499 prefix. With Silicon, this mapping was made regular, i.e. all getters share the same ``get`` prefix. Compatibility
500 getters were retained as simple adapters, so that both ``boolean isFoo()`` and ``boolean getFoo()`` were available.
501
502 In this release these compatibility methods are no longer generated, as detailed in
503 `this MD-SAL issue <https://jira.opendaylight.org/browse/MDSAL-659>`__.
504
505
506 Producer/Consumer APIs removed
507 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
508 ``DOMDataTreeShard`` as well as ``DataTreeProducer``, ``DataTreeConsumer`` and related class were removed. These
509 APIs failed to get productized and were very problematic in a clustered setting and they were impossible to migrate
510 to gradually. A future version of MD-SAL will define a set of replacement interfaces along with a migration guide,
511 allowing for gradual migration.
512
513
514 Controller Impacts
515 ------------------
516
517 Distributed Datastore backwards compatibility reduced to Sodium SR1
518 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
519 Backwards compatibility glue in prior versions spanned as far back as Boron release. In this release a number of glue
520 items were removed, removing compatibility with datastore versions prior to Sodium SR1.
521
522
523 Prefix-based shards removed
524 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
525 Prefix-based sharding implementation in the Distributed Datastore has been removed as a consequence of MD-SAL APIs
526 it implemented being removed.
527
528
529 Message Bus component removed
530 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
531 The experimental ``messagebus`` component was removed. This component has had only one implementation in NETCONF
532 project. The combination has been a proof of concept and was never productized nor has it been tested in real world
533 for the past 4 years.
534
535
536 `opendaylight-topology` and `opendaylight-inventory` removed
537 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
538 These two sets of models are only used in OpenFlow plugin and its users. Most of the concepts they introduce have
539 been superseded by IETF-standardized ``ietf-network`` and related models. These models are removed from the controller
540 project and reintroduced in OpenFlow Plugin. Users are advised to either consume them from OpenFlow, or migrate to
541 using `RFC8345 <https://datatracker.ietf.org/doc/html/rfc8345>`__ instead.
542
543
544 Removed support for deprecated `datastore.cfg` properties
545 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
546 The following properties in `datastore.cfg` have been deprecated and were no-ops in previous releases:
547   * ``max-shard-data-change-executor-pool-size``
548   * ``max-shard-data-change-executor-queue-size``
549   * ``max-shard-data-change-listener-queue-size``
550   * ``max-shard-data-store-executor-queue-size``
551
552 This release no longer recognizes these properties and treats them as errors.
553