Merge ~lloydwaltersj/maas:deprecation-marker into maas:master

Proposed by Jack Lloyd-Walters
Status: Merged
Approved by: Jack Lloyd-Walters
Approved revision: 157ceeecc564aa0d9b116a014c861faa4f0e77a3
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~lloydwaltersj/maas:deprecation-marker
Merge into: maas:master
Diff against target: 303 lines (+109/-22)
7 files modified
src/maasserver/api/commissioning_scripts.py (+6/-7)
src/maasserver/api/networks.py (+10/-6)
src/maasserver/api/nodes.py (+2/-0)
src/maasserver/api/pods.py (+8/-8)
src/maasserver/api/support.py (+56/-1)
src/maasserver/api/tests/test_support.py (+23/-0)
src/maasserver/exceptions.py (+4/-0)
Reviewer Review Type Date Requested Status
Adam Collard (community) Approve
MAAS Lander Approve
Review via email: mp+429164@code.launchpad.net

Commit message

Add deprecated decorator for use with MAAS Api

Description of the change

Api endpoints and methods that are deprecated have very freeform markings in docstrings and endpoint names.

This should standardise that, as well as expose a new "deprecated" attribute that can be used to programatically determine if an operation/endpoint is deprecated.

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/437/consoleText
COMMIT: 048b4f3cd370b5e52cdb7899d3629f205ded487a

review: Needs Fixing
ed7efec... by Jack Lloyd-Walters

Change how docstring is modified

6a8e4e9... by Jack Lloyd-Walters

formatting

c9655ff... by Jack Lloyd-Walters

remove leftover print

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: c9655ff1871ecb56eb8da345922792e0572af4d4

review: Approve
6454d9a... by Jack Lloyd-Walters

use func_name for function name

e1e319c... by Jack Lloyd-Walters

Change docstring ordering

80bed44... by Jack Lloyd-Walters

formatting

7c8b7bf... by Jack Lloyd-Walters

change if-elif-if to if-elif-elise

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 6454d9ad27a9bebd1267d3c9e7fb07a3d56a7b03

review: Approve
Revision history for this message
Alberto Donato (ack) :
Revision history for this message
Jack Lloyd-Walters (lloydwaltersj) :
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 7c8b7bf7767392ae95a972275a915fab9035a507

review: Approve
9327ce1... by Jack Lloyd-Walters

apply suggestions

Revision history for this message
Adam Collard (adam-collard) :
review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 9327ce1ca96652affd8a0cf6a94793e2512baa9e

review: Approve
0f2e286... by Jack Lloyd-Walters

seperate methods to handle docstrings

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/452/consoleText
COMMIT: 0f2e286bcca3224239895c72bd54a58f16a4bda0

review: Needs Fixing
Revision history for this message
Jack Lloyd-Walters (lloydwaltersj) wrote :

jenkins: !test

4938600... by Jack Lloyd-Walters

bring branch up to parity

157ceee... by Jack Lloyd-Walters

Change order

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/453/consoleText
COMMIT: 0f2e286bcca3224239895c72bd54a58f16a4bda0

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b deprecation-marker lp:~lloydwaltersj/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 157ceeecc564aa0d9b116a014c861faa4f0e77a3

review: Approve
Revision history for this message
Adam Collard (adam-collard) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/api/commissioning_scripts.py b/src/maasserver/api/commissioning_scripts.py
index 11b2981..477b688 100644
--- a/src/maasserver/api/commissioning_scripts.py
+++ b/src/maasserver/api/commissioning_scripts.py
@@ -11,7 +11,8 @@ from django.shortcuts import get_object_or_404
11from django.urls import reverse11from django.urls import reverse
12from piston3.utils import rc12from piston3.utils import rc
1313
14from maasserver.api.support import OperationsHandler14from maasserver.api.scripts import NodeScriptHandler, NodeScriptsHandler
15from maasserver.api.support import deprecated, OperationsHandler
15from maasserver.api.utils import get_mandatory_param16from maasserver.api.utils import get_mandatory_param
16from maasserver.audit import create_audit_event17from maasserver.audit import create_audit_event
17from maasserver.enum import ENDPOINT18from maasserver.enum import ENDPOINT
@@ -29,16 +30,15 @@ def get_content_parameter(request):
29 return content_file.read()30 return content_file.read()
3031
3132
33@deprecated(use=NodeScriptsHandler)
32class CommissioningScriptsHandler(OperationsHandler):34class CommissioningScriptsHandler(OperationsHandler):
33 """35 """
34 Manage custom commissioning scripts.36 Manage custom commissioning scripts.
3537
36 This functionality is only available to administrators.38 This functionality is only available to administrators.
37
38 This endpoint has been deprecated in favor of the node-scripts endpoint.
39 """39 """
4040
41 api_doc_section_name = "Commissioning scripts (deprecated)"41 api_doc_section_name = "Commissioning scripts"
4242
43 update = delete = None43 update = delete = None
4444
@@ -109,16 +109,15 @@ class CommissioningScriptsHandler(OperationsHandler):
109 return ("commissioning_scripts_handler", [])109 return ("commissioning_scripts_handler", [])
110110
111111
112@deprecated(use=NodeScriptHandler)
112class CommissioningScriptHandler(OperationsHandler):113class CommissioningScriptHandler(OperationsHandler):
113 """114 """
114 Manage a custom commissioning script.115 Manage a custom commissioning script.
115116
116 This functionality is only available to administrators.117 This functionality is only available to administrators.
117
118 This endpoint has been deprecated in favor of the node-script endpoint.
119 """118 """
120119
121 api_doc_section_name = "Commissioning script (deprecated)"120 api_doc_section_name = "Commissioning script"
122121
123 # Relies on Piston's built-in DELETE implementation. There is no POST.122 # Relies on Piston's built-in DELETE implementation. There is no POST.
124 create = None123 create = None
diff --git a/src/maasserver/api/networks.py b/src/maasserver/api/networks.py
index 0810bd0..bbe0eb8 100644
--- a/src/maasserver/api/networks.py
+++ b/src/maasserver/api/networks.py
@@ -7,7 +7,13 @@
7from django.urls import reverse7from django.urls import reverse
8from piston3.utils import rc8from piston3.utils import rc
99
10from maasserver.api.support import admin_method, operation, OperationsHandler10from maasserver.api.subnets import SubnetHandler, SubnetsHandler
11from maasserver.api.support import (
12 admin_method,
13 deprecated,
14 operation,
15 OperationsHandler,
16)
11from maasserver.exceptions import MAASAPIValidationError17from maasserver.exceptions import MAASAPIValidationError
12from maasserver.forms import NetworksListingForm18from maasserver.forms import NetworksListingForm
13from maasserver.models import Interface, Node, Subnet19from maasserver.models import Interface, Node, Subnet
@@ -39,14 +45,13 @@ def render_networks_json(subnets):
39 return [render_network_json(subnet) for subnet in subnets]45 return [render_network_json(subnet) for subnet in subnets]
4046
4147
48@deprecated(use=SubnetHandler)
42class NetworkHandler(OperationsHandler):49class NetworkHandler(OperationsHandler):
43 """50 """
44 Manage a network.51 Manage a network.
45
46 This endpoint is deprecated. Use the new 'subnet' endpoint instead.
47 """52 """
4853
49 api_doc_section_name = "Network (deprecated)"54 api_doc_section_name = "Network"
50 create = None55 create = None
5156
52 def read(self, request, name):57 def read(self, request, name):
@@ -150,11 +155,10 @@ class NetworkHandler(OperationsHandler):
150 return ("network_handler", (name,))155 return ("network_handler", (name,))
151156
152157
158@deprecated(use=SubnetsHandler)
153class NetworksHandler(OperationsHandler):159class NetworksHandler(OperationsHandler):
154 """160 """
155 Manage the networks.161 Manage the networks.
156
157 This endpoint is deprecated. Use the new 'subnets' endpoint instead.
158 """162 """
159163
160 api_doc_section_name = "Networks"164 api_doc_section_name = "Networks"
diff --git a/src/maasserver/api/nodes.py b/src/maasserver/api/nodes.py
index 3ff069c..04c2457 100644
--- a/src/maasserver/api/nodes.py
+++ b/src/maasserver/api/nodes.py
@@ -20,6 +20,7 @@ from piston3.utils import rc
20from maasserver.api.support import (20from maasserver.api.support import (
21 admin_method,21 admin_method,
22 AnonymousOperationsHandler,22 AnonymousOperationsHandler,
23 deprecated,
23 operation,24 operation,
24 OperationsHandler,25 OperationsHandler,
25)26)
@@ -914,6 +915,7 @@ class WorkloadAnnotationsMixin:
914 return node915 return node
915916
916 @operation(idempotent=False)917 @operation(idempotent=False)
918 @deprecated(use=set_workload_annotations)
917 def set_owner_data(self, request, system_id):919 def set_owner_data(self, request, system_id):
918 """@description-title Deprecated, use set-workload-annotations.920 """@description-title Deprecated, use set-workload-annotations.
919 @description Deprecated, use set-workload-annotations instead."""921 @description Deprecated, use set-workload-annotations instead."""
diff --git a/src/maasserver/api/pods.py b/src/maasserver/api/pods.py
index 8af6775..58c8910 100644
--- a/src/maasserver/api/pods.py
+++ b/src/maasserver/api/pods.py
@@ -9,7 +9,12 @@ from django.urls import reverse
9from formencode.validators import String9from formencode.validators import String
10from piston3.utils import rc10from piston3.utils import rc
1111
12from maasserver.api.support import admin_method, operation, OperationsHandler12from maasserver.api.support import (
13 admin_method,
14 deprecated,
15 operation,
16 OperationsHandler,
17)
13from maasserver.api.utils import get_mandatory_param18from maasserver.api.utils import get_mandatory_param
14from maasserver.exceptions import MAASAPIValidationError, PodProblem19from maasserver.exceptions import MAASAPIValidationError, PodProblem
15from maasserver.forms.pods import ComposeMachineForm, DeletePodForm, PodForm20from maasserver.forms.pods import ComposeMachineForm, DeletePodForm, PodForm
@@ -423,12 +428,10 @@ class VmHostHandler(OperationsHandler):
423428
424# Pods are being renamed to VM hosts. Keep the old name on the API as well for429# Pods are being renamed to VM hosts. Keep the old name on the API as well for
425# backwards-compatibility.430# backwards-compatibility.
431@deprecated(use=VmHostHandler)
426class PodHandler(VmHostHandler):432class PodHandler(VmHostHandler):
427 """433 """
428 Manage an individual Pod.434 Manage an individual Pod.
429
430 The /pod/ API endpoint is deprecated. Please use the /vm-host/ one instead.
431
432 """435 """
433436
434 api_doc_section_name = "Pod"437 api_doc_section_name = "Pod"
@@ -531,13 +534,10 @@ class VmHostsHandler(OperationsHandler):
531534
532# Pods are being renamed to VM hosts. Keep the old name on the API as well for535# Pods are being renamed to VM hosts. Keep the old name on the API as well for
533# backwards-compatibility.536# backwards-compatibility.
537@deprecated(use=VmHostsHandler)
534class PodsHandler(VmHostsHandler):538class PodsHandler(VmHostsHandler):
535 """539 """
536 Manage the collection of all the pods in the MAAS.540 Manage the collection of all the pods in the MAAS.
537
538 The /pods/ API endpoint is deprecated. Please use the /vm-hosts/ one
539 instead.
540
541 """541 """
542542
543 api_doc_section_name = "Pods"543 api_doc_section_name = "Pods"
diff --git a/src/maasserver/api/support.py b/src/maasserver/api/support.py
index d86502f..db8b222 100644
--- a/src/maasserver/api/support.py
+++ b/src/maasserver/api/support.py
@@ -14,6 +14,7 @@ __all__ = [
1414
15from abc import ABCMeta, abstractproperty15from abc import ABCMeta, abstractproperty
16from functools import wraps16from functools import wraps
17import inspect
17import re18import re
1819
19from django.core.exceptions import PermissionDenied20from django.core.exceptions import PermissionDenied
@@ -26,7 +27,11 @@ from piston3.resource import Resource
26from piston3.utils import HttpStatusCode, rc27from piston3.utils import HttpStatusCode, rc
2728
28from maasserver.api.doc import get_api_description29from maasserver.api.doc import get_api_description
29from maasserver.exceptions import MAASAPIBadRequest, MAASAPIValidationError30from maasserver.exceptions import (
31 MAASAPIBadRequest,
32 MAASAPIValidationError,
33 MAASBadDeprecation,
34)
30from maasserver.utils.orm import get_one35from maasserver.utils.orm import get_one
31from provisioningserver.logger import LegacyLogger36from provisioningserver.logger import LegacyLogger
3237
@@ -142,6 +147,56 @@ def operation(idempotent, exported_as=None):
142 return _decorator147 return _decorator
143148
144149
150def deprecated(use):
151 """Decorator to note a method or class is deprecated on the API.
152
153 :param use: Name of the method or class that should be used in place of this method"""
154
155 # TODO: Determine any other behaviours we might want from this decorator in future
156
157 def update_method_docstring(func):
158 doc = func.__doc__ if func.__doc__ else ""
159 depr = f"This operation has been deprecated in favour of '{func_name(use)} {func_name(func.deprecated)}'"
160 if "@description" in doc:
161 description = doc.split("@description ")[1].split(".")[0]
162 func.__doc = doc.replace(description, f"{description}. {depr}")
163 else:
164 func.__doc__ = f"{doc}\n{depr}."
165
166 def update_class_docstring(cls):
167 cls.__doc__ = f"{cls.__doc__}\nThe '{func_name(cls)}' endpoint has been deprecated in favour of '{func_name(use)}'."
168 if "(deprecated)" not in cls.api_doc_section_name:
169 cls.api_doc_section_name += " (deprecated)"
170
171 def func_name(func):
172 return re.sub(
173 "[_ ]", "-", getattr(func, "api_doc_section_name", func.__name__)
174 )
175
176 def _decorator(func):
177 if type(func) is not type(use):
178 raise MAASBadDeprecation(
179 f"{func_name(func)} is deprecated in favour of {func_name(use)}, but {type(use)} is not a valid replacement for {type(func)}"
180 )
181 func.deprecated = use
182 # if an endpoint (class) was passed to the decorator, apply the decorator to all of it's methods too
183 if isinstance(func, type):
184 apply_to_methods(func)
185 update_class_docstring(func)
186 else:
187 update_method_docstring(func)
188 return func
189
190 def apply_to_methods(cls):
191 for name, method in inspect.getmembers(cls, inspect.isfunction):
192 new_method = getattr(use, name, None)
193 if new_method:
194 method.deprecated = new_method
195 update_method_docstring(method)
196
197 return _decorator
198
199
145METHOD_RESERVED_ADMIN = "This method is reserved for admin users."200METHOD_RESERVED_ADMIN = "This method is reserved for admin users."
146201
147202
diff --git a/src/maasserver/api/tests/test_support.py b/src/maasserver/api/tests/test_support.py
index 62fd55e..bbc04c9 100644
--- a/src/maasserver/api/tests/test_support.py
+++ b/src/maasserver/api/tests/test_support.py
@@ -15,6 +15,7 @@ from maasserver.api.doc import get_api_description
15from maasserver.api.support import (15from maasserver.api.support import (
16 admin_method,16 admin_method,
17 AdminRestrictedResource,17 AdminRestrictedResource,
18 deprecated,
18 Emitter,19 Emitter,
19 OperationsHandlerMixin,20 OperationsHandlerMixin,
20 OperationsResource,21 OperationsResource,
@@ -180,6 +181,28 @@ class TestAdminMethodDecorator(MAASServerTestCase):
180 self.assertEqual((return_value, [call()]), (response, mock.mock_calls))181 self.assertEqual((return_value, [call()]), (response, mock.mock_calls))
181182
182183
184class TestDeprecatedMethodDecorator(MAASServerTestCase):
185 def test_function_marked_as_deprecated(self):
186 def api_replacement_method(self, request):
187 pass
188
189 @deprecated(use=api_replacement_method)
190 def api_method(self, request):
191 pass
192
193 self.assertEqual(api_method.deprecated, api_replacement_method)
194
195 def test_class_marked_as_deprecated(self):
196 class api_replacement_endpoint:
197 api_doc_section_name = "Replacement"
198
199 @deprecated(use=api_replacement_endpoint)
200 class api_endpoint:
201 api_doc_section_name = "Deprecated"
202
203 self.assertEqual(api_endpoint.deprecated, api_replacement_endpoint)
204
205
183class TestOperationsHandlerMixin(MAASTestCase):206class TestOperationsHandlerMixin(MAASTestCase):
184 """Tests for :py:class:`maasserver.api.support.OperationsHandlerMixin`."""207 """Tests for :py:class:`maasserver.api.support.OperationsHandlerMixin`."""
185208
diff --git a/src/maasserver/exceptions.py b/src/maasserver/exceptions.py
index b811206..4ebae20 100644
--- a/src/maasserver/exceptions.py
+++ b/src/maasserver/exceptions.py
@@ -245,3 +245,7 @@ class StorageClearProblem(MAASAPIException):
245245
246class NetworkingResetProblem(MAASException):246class NetworkingResetProblem(MAASException):
247 """Raised when an issue occurs that prevents resetting networking configuration."""247 """Raised when an issue occurs that prevents resetting networking configuration."""
248
249
250class MAASBadDeprecation(MAASException):
251 """Raised when an API endpoint or operation has it's deprecation incorrectly assigned."""

Subscribers

People subscribed via source and target branches