Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-110243 / 12.0 / Allow endpoints to specify explicit http methods (by sonicaj) #6819

Merged
merged 2 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/middlewared/middlewared/plugins/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from middlewared.logger import CrashReporting
from middlewared.schema import accepts, Bool, Dict, Int, IPAddr, List, Str
from middlewared.service import (
CallError, ConfigService, no_auth_required, job, pass_app, private, Service, throttle, ValidationErrors
CallError, ConfigService, no_auth_required, job, pass_app, private, rest_api_metadata,
Service, throttle, ValidationErrors
)
import middlewared.sqlalchemy as sa
from middlewared.utils import Popen, run, start_daemon_thread, sw_buildtime, sw_version, osc
Expand Down Expand Up @@ -1303,6 +1304,7 @@ async def do_update(self, data):

return await self.config()

@rest_api_metadata(extra_methods=['GET'])
@accepts(Int('delay', default=3, validators=[Range(min=0)]))
async def ui_restart(self, delay):
"""
Expand Down
5 changes: 5 additions & 0 deletions src/middlewared/middlewared/restful.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ async def register_resources(self):
res_kwargs['post'] = methodname
else:
res_kwargs['get'] = methodname
for rest_method in map(str.lower, (method['extra_methods'] or [])):
assert rest_method in ('get',)
# Only allow get for now as that's the only use case we have for now NAS-110243
res_kwargs[rest_method] = methodname

Resource(self, self.middleware, short_methodname, service['config'], parent=parent, **res_kwargs)
await asyncio.sleep(0) # Force context switch

Expand Down
19 changes: 19 additions & 0 deletions src/middlewared/middlewared/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,23 @@ def wrapper(fn):
return wrapper


def rest_api_metadata(extra_methods=None):
"""
Allow having endpoints specify explicit rest methods.

Explicit methods should be a list which specifies what methods the function should be available
at other then the default one it is already going to be. This is useful when we want to maintain
backwards compatibility with endpoints which were not expecting payload before but are now and users
still would like to consume them with previous method which would be GET whereas it's POST now.
"""
def wrapper(fn):
fn._rest_api_metadata = {
'extra_methods': extra_methods,
}
return fn
return wrapper


def periodic(interval, run_on_start=True):
def wrapper(fn):
fn._periodic = PeriodicTaskDescriptor(interval, run_on_start)
Expand Down Expand Up @@ -969,6 +986,8 @@ def get_methods(self, service=None):
'no_auth_required': hasattr(method, '_no_auth_required'),
'filterable': hasattr(method, '_filterable'),
'pass_application': hasattr(method, '_pass_app'),
'extra_methods': method._rest_api_metadata['extra_methods'] if hasattr(
method, '_rest_api_metadata') else None,
'require_websocket': hasattr(method, '_pass_app') and not method._pass_app['rest'],
'job': hasattr(method, '_job'),
'downloadable': hasattr(method, '_job') and 'output' in method._job['pipes'],
Expand Down