mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-19 05:21:55 -06:00
Closes #4918: Add a REST API endpoint which returns NetBox's current operational status
This commit is contained in:
parent
c0c5f52ed9
commit
80c142ab7c
@ -46,6 +46,7 @@ All end-to-end cable paths are now cached using the new CablePath model. This al
|
|||||||
* [#1692](https://github.com/netbox-community/netbox/issues/1692) - Allow assigment of inventory items to parent items in web UI
|
* [#1692](https://github.com/netbox-community/netbox/issues/1692) - Allow assigment of inventory items to parent items in web UI
|
||||||
* [#2179](https://github.com/netbox-community/netbox/issues/2179) - Support the assignment of multiple port numbers for services
|
* [#2179](https://github.com/netbox-community/netbox/issues/2179) - Support the assignment of multiple port numbers for services
|
||||||
* [#4897](https://github.com/netbox-community/netbox/issues/4897) - Allow filtering by content type identified as `<app>.<model>` string
|
* [#4897](https://github.com/netbox-community/netbox/issues/4897) - Allow filtering by content type identified as `<app>.<model>` string
|
||||||
|
* [#4918](https://github.com/netbox-community/netbox/issues/4918) - Add a REST API endpoint (`/api/status/`) which returns NetBox's current operational status
|
||||||
* [#4956](https://github.com/netbox-community/netbox/issues/4956) - Include inventory items on primary device view
|
* [#4956](https://github.com/netbox-community/netbox/issues/4956) - Include inventory items on primary device view
|
||||||
* [#5003](https://github.com/netbox-community/netbox/issues/5003) - CSV import now accepts slug values for choice fields
|
* [#5003](https://github.com/netbox-community/netbox/issues/5003) - CSV import now accepts slug values for choice fields
|
||||||
* [#5146](https://github.com/netbox-community/netbox/issues/5146) - Add custom fields support for cables, power panels, rack reservations, and virtual chassis
|
* [#5146](https://github.com/netbox-community/netbox/issues/5146) - Add custom fields support for cables, power panels, rack reservations, and virtual chassis
|
||||||
@ -63,7 +64,8 @@ All end-to-end cable paths are now cached using the new CablePath model. This al
|
|||||||
### REST API Changes
|
### REST API Changes
|
||||||
|
|
||||||
* Added support for `PUT`, `PATCH`, and `DELETE` operations on list endpoints (bulk update and delete)
|
* Added support for `PUT`, `PATCH`, and `DELETE` operations on list endpoints (bulk update and delete)
|
||||||
* Added `/extras/content-types/` endpoint for Django ContentTypes
|
* Added the `/extras/content-types/` endpoint for Django ContentTypes
|
||||||
|
* Added the `/status/` endpoint to convey NetBox's current status
|
||||||
* circuits.CircuitTermination:
|
* circuits.CircuitTermination:
|
||||||
* Added the `/trace/` endpoint
|
* Added the `/trace/` endpoint
|
||||||
* Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
|
* Replaced `connection_status` with `connected_endpoint_reachable` (boolean)
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import platform
|
||||||
|
|
||||||
|
from django import __version__ as DJANGO_VERSION
|
||||||
|
from django.apps import apps
|
||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import ProtectedError
|
from django.db.models import ProtectedError
|
||||||
|
from django_rq.queues import get_connection
|
||||||
from rest_framework import mixins, status
|
from rest_framework import mixins, status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
from rq.worker import Worker
|
||||||
|
|
||||||
from netbox.api import BulkOperationSerializer
|
from netbox.api import BulkOperationSerializer
|
||||||
from netbox.api.exceptions import SerializerNotFound
|
from netbox.api.exceptions import SerializerNotFound
|
||||||
@ -218,3 +225,42 @@ class ModelViewSet(mixins.CreateModelMixin,
|
|||||||
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
||||||
|
|
||||||
return super().perform_destroy(instance)
|
return super().perform_destroy(instance)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Views
|
||||||
|
#
|
||||||
|
|
||||||
|
class StatusView(APIView):
|
||||||
|
"""
|
||||||
|
Provide a lightweight read-only endpoint for conveying NetBox's current operational status.
|
||||||
|
"""
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
# Gather the version number from all installed Django apps
|
||||||
|
installed_apps = {}
|
||||||
|
for app_config in apps.get_app_configs():
|
||||||
|
app = app_config.module
|
||||||
|
version = getattr(app, 'VERSION', getattr(app, '__version__', None))
|
||||||
|
if version:
|
||||||
|
if type(version) is tuple:
|
||||||
|
version = '.'.join(str(n) for n in version)
|
||||||
|
installed_apps[app_config.name] = version
|
||||||
|
installed_apps = {k: v for k, v in sorted(installed_apps.items())}
|
||||||
|
|
||||||
|
# Gather installed plugins
|
||||||
|
plugins = {}
|
||||||
|
for plugin_name in settings.PLUGINS:
|
||||||
|
plugin_config = apps.get_app_config(plugin_name)
|
||||||
|
plugins[plugin_name] = getattr(plugin_config, 'version', None)
|
||||||
|
plugins = {k: v for k, v in sorted(plugins.items())}
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
'django-version': DJANGO_VERSION,
|
||||||
|
'installed-apps': installed_apps,
|
||||||
|
'netbox-version': settings.VERSION,
|
||||||
|
'plugins': plugins,
|
||||||
|
'python-version': platform.python_version(),
|
||||||
|
'rq-workers-running': Worker.count(get_connection('default')),
|
||||||
|
})
|
||||||
|
@ -6,8 +6,13 @@ from utilities.testing import APITestCase
|
|||||||
class AppTest(APITestCase):
|
class AppTest(APITestCase):
|
||||||
|
|
||||||
def test_root(self):
|
def test_root(self):
|
||||||
|
|
||||||
url = reverse('api-root')
|
url = reverse('api-root')
|
||||||
response = self.client.get('{}?format=api'.format(url), **self.header)
|
response = self.client.get('{}?format=api'.format(url), **self.header)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
url = reverse('api-status')
|
||||||
|
response = self.client.get('{}?format=api'.format(url), **self.header)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -6,6 +6,7 @@ from drf_yasg import openapi
|
|||||||
from drf_yasg.views import get_schema_view
|
from drf_yasg.views import get_schema_view
|
||||||
|
|
||||||
from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns
|
from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns
|
||||||
|
from netbox.api.views import StatusView
|
||||||
from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView
|
from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView
|
||||||
from users.views import LoginView, LogoutView
|
from users.views import LoginView, LogoutView
|
||||||
from .admin import admin_site
|
from .admin import admin_site
|
||||||
@ -55,6 +56,7 @@ _patterns = [
|
|||||||
path('api/tenancy/', include('tenancy.api.urls')),
|
path('api/tenancy/', include('tenancy.api.urls')),
|
||||||
path('api/users/', include('users.api.urls')),
|
path('api/users/', include('users.api.urls')),
|
||||||
path('api/virtualization/', include('virtualization.api.urls')),
|
path('api/virtualization/', include('virtualization.api.urls')),
|
||||||
|
path('api/status/', StatusView.as_view(), name='api-status'),
|
||||||
path('api/docs/', schema_view.with_ui('swagger'), name='api_docs'),
|
path('api/docs/', schema_view.with_ui('swagger'), name='api_docs'),
|
||||||
path('api/redoc/', schema_view.with_ui('redoc'), name='api_redocs'),
|
path('api/redoc/', schema_view.with_ui('redoc'), name='api_redocs'),
|
||||||
re_path(r'^api/swagger(?P<format>.json|.yaml)$', schema_view.without_ui(), name='schema_swagger'),
|
re_path(r'^api/swagger(?P<format>.json|.yaml)$', schema_view.without_ui(), name='schema_swagger'),
|
||||||
|
@ -342,6 +342,7 @@ class APIRootView(APIView):
|
|||||||
('ipam', reverse('ipam-api:api-root', request=request, format=format)),
|
('ipam', reverse('ipam-api:api-root', request=request, format=format)),
|
||||||
('plugins', reverse('plugins-api:api-root', request=request, format=format)),
|
('plugins', reverse('plugins-api:api-root', request=request, format=format)),
|
||||||
('secrets', reverse('secrets-api:api-root', request=request, format=format)),
|
('secrets', reverse('secrets-api:api-root', request=request, format=format)),
|
||||||
|
('status', reverse('api-status', request=request, format=format)),
|
||||||
('tenancy', reverse('tenancy-api:api-root', request=request, format=format)),
|
('tenancy', reverse('tenancy-api:api-root', request=request, format=format)),
|
||||||
('users', reverse('users-api:api-root', request=request, format=format)),
|
('users', reverse('users-api:api-root', request=request, format=format)),
|
||||||
('virtualization', reverse('virtualization-api:api-root', request=request, format=format)),
|
('virtualization', reverse('virtualization-api:api-root', request=request, format=format)),
|
||||||
|
Loading…
Reference in New Issue
Block a user