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

How to add API route for a check plugin #703

Closed
jakubgs opened this issue Dec 11, 2020 · 7 comments
Closed

How to add API route for a check plugin #703

jakubgs opened this issue Dec 11, 2020 · 7 comments

Comments

@jakubgs
Copy link

jakubgs commented Dec 11, 2020

I've created a custom check plugin for my use case:
https://github.com/status-im/cabot-check-status-go

And it works great, but the problem is that there is no API route available to programatically create the checks.

How would one go about adding the API route to a plugin? Is this even doable within a plugin?

Or would it require changes to Cabot itself?

@jakubgs
Copy link
Author

jakubgs commented Dec 11, 2020

I tried adding this to my model.py:

from rest_framework import routers, serializers, viewsets, mixins
from cabot import create_viewset, status_check_fields

router = routers.DefaultRouter()

router.register(r'status_go_checks', create_viewset(
    arg_model=StatusGoStatusCheck,
    arg_fields=status_check_fields + (
        'node_type',
        'enode',
    ),
))

But worker fails to start with:

Traceback (most recent call last):
  File "/usr/local/bin/gunicorn", line 8, in <module>
    sys.exit(run())
  File "/usr/local/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 74, in run
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
  File "/usr/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 203, in run
    super(Application, self).run()
  File "/usr/local/lib/python2.7/site-packages/gunicorn/app/base.py", line 72, in run
    Arbiter(self).run()
  File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 231, in run
    self.halt(reason=inst.reason, exit_status=inst.exit_status)
  File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 344, in halt
    self.stop()
  File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 393, in stop
    time.sleep(0.1)
  File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 244, in handle_chld
    self.reap_workers()
  File "/usr/local/lib/python2.7/site-packages/gunicorn/arbiter.py", line 524, in reap_workers
    raise HaltServer(reason, self.WORKER_BOOT_ERROR)
gunicorn.errors.HaltServer: <HaltServer 'Worker failed to boot.' 3>

@jakubgs
Copy link
Author

jakubgs commented Jan 11, 2021

Worker shows in logs this:

Traceback (most recent call last):
  File "/usr/local/bin/celery", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/site-packages/celery/__main__.py", line 16, in main
    _main()
  File "/usr/local/lib/python2.7/site-packages/celery/bin/celery.py", line 322, in main
    cmd.execute_from_commandline(argv)
  File "/usr/local/lib/python2.7/site-packages/celery/bin/celery.py", line 496, in execute_from_commandline
    super(CeleryCommand, self).execute_from_commandline(argv)))
  File "/usr/local/lib/python2.7/site-packages/celery/bin/base.py", line 275, in execute_from_commandline
    return self.handle_argv(self.prog_name, argv[1:])
  File "/usr/local/lib/python2.7/site-packages/celery/bin/celery.py", line 488, in handle_argv
    return self.execute(command, argv)
  File "/usr/local/lib/python2.7/site-packages/celery/bin/celery.py", line 420, in execute
    ).run_from_argv(self.prog_name, argv[1:], command=argv[0])
  File "/usr/local/lib/python2.7/site-packages/celery/bin/worker.py", line 223, in run_from_argv
    return self(*args, **options)
  File "/usr/local/lib/python2.7/site-packages/celery/bin/base.py", line 238, in __call__
    ret = self.run(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/celery/bin/worker.py", line 257, in run
    **kwargs)
  File "/usr/local/lib/python2.7/site-packages/celery/worker/worker.py", line 96, in __init__
    self.app.loader.init_worker()
  File "/usr/local/lib/python2.7/site-packages/celery/loaders/base.py", line 114, in init_worker
    self.import_default_modules()
  File "/usr/local/lib/python2.7/site-packages/celery/loaders/base.py", line 108, in import_default_modules
    raise response
ImportError: cannot import name create_viewset

@jakubgs
Copy link
Author

jakubgs commented Jan 15, 2021

I think I figured it out, based on looking at this method:

cabot/cabot/urls.py

Lines 174 to 187 in eb0b354

def append_plugin_urls():
"""
Appends plugin specific URLs to the urlpatterns variable.
"""
global urlpatterns
for plugin in settings.CABOT_PLUGINS_ENABLED_PARSED:
try:
_module = import_module('%s.urls' % plugin)
except ImportError:
pass
else:
urlpatterns += [
url(r'^plugins/%s/' % plugin, include('%s.urls' % plugin))
]

Specifically this part:

             urlpatterns += [ 
                 url(r'^plugins/%s/' % plugin, include('%s.urls' % plugin)) 
             ] 

Which means that the contents of urls.py file in a plugin are loaded into urlpatterns under plugins/.

@jakubgs
Copy link
Author

jakubgs commented Jan 15, 2021

I managed to get a route working by adding this:

from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter

from cabot.rest_urls import create_viewset, status_check_fields

from .models import StatusGoStatusCheck

api_router = DefaultRouter()
api_router.register(r'status_go_checks', create_viewset(
    arg_model=StatusGoStatusCheck,
    arg_fields=status_check_fields + (
        'node_type',
        'enode',
    ),
))

urlpatterns = [
    url(r'^api/', include(api_router.urls)),
    # other routes omitted
]

And by doing this I managed to find my route using the cabot shell command:

>>> from cabot.urls import urlpatterns
>>> urlpatterns[-2]
<RegexURLResolver <module 'cabot_check_status_go.urls' from '/usr/local/lib/python2.7/site-packages/cabot_check_status_go/urls.pyc'> (None:None) ^plugins/cabot_check_status_go/>
>>> urlpatterns[-2].url_patterns
[<RegexURLResolver <RegexURLPattern list> (None:None) ^api/>]

Which showed me that I can now access the API under: /plugins/cabot_check_status_go/api/status_go_checks/

@jakubgs
Copy link
Author

jakubgs commented Jan 15, 2021

I'm not sure if there is an easy way to put this directly under /api/ at the root, but putting it under /plugins/cabot_check_status_go/ is good enough for me.

@dbuxton
Copy link
Contributor

dbuxton commented Jan 15, 2021

@jakubgs I'm not sure you meant to post this on this repo?

@jakubgs
Copy link
Author

jakubgs commented Jan 16, 2021

Heh, true, that's what happens when you have too many tabs and working on too many issues at the same time.

@jakubgs jakubgs closed this as completed Jan 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants