From 47617903df714087a6571d7828831841a7791ff6 Mon Sep 17 00:00:00 2001 From: Gary Snider <75227981+gsnider2195@users.noreply.github.com> Date: Fri, 15 Nov 2024 08:15:46 -0800 Subject: [PATCH] Fix constance being accessed before database is ready and other fixes (#341) --- changes/341.added | 1 + changes/341.fixed | 4 + changes/341.housekeeping | 1 + changes/341.removed | 1 + development/nautobot_config.py | 38 ++- nautobot_chatops/api/urls.py | 47 +--- nautobot_chatops/api/views/mattermost.py | 11 +- nautobot_chatops/api/views/ms_teams.py | 4 +- nautobot_chatops/api/views/slack.py | 13 +- nautobot_chatops/api/views/webex.py | 4 +- .../integrations/grafana/api/__init__.py | 1 - .../integrations/grafana/api/urls.py | 15 -- .../grafana/api/views/__init__.py | 5 - .../integrations/grafana/api/views/generic.py | 11 - .../integrations/grafana/diffsync/sync.py | 44 +++- .../integrations/grafana/navigation.py | 6 +- .../integrations/grafana/tables.py | 20 +- nautobot_chatops/integrations/grafana/urls.py | 14 +- .../integrations/grafana/views.py | 216 +++++++++++------- nautobot_chatops/models.py | 4 +- nautobot_chatops/navigation.py | 7 +- nautobot_chatops/tables.py | 7 + .../grafana_disabled.html | 16 ++ nautobot_chatops/urls.py | 17 +- nautobot_chatops/views.py | 19 ++ nautobot_chatops/workers/__init__.py | 6 +- 26 files changed, 304 insertions(+), 228 deletions(-) create mode 100644 changes/341.added create mode 100644 changes/341.fixed create mode 100644 changes/341.housekeeping create mode 100644 changes/341.removed delete mode 100644 nautobot_chatops/integrations/grafana/api/__init__.py delete mode 100644 nautobot_chatops/integrations/grafana/api/urls.py delete mode 100644 nautobot_chatops/integrations/grafana/api/views/__init__.py delete mode 100644 nautobot_chatops/integrations/grafana/api/views/generic.py create mode 100644 nautobot_chatops/templates/nautobot_chatops_grafana/grafana_disabled.html diff --git a/changes/341.added b/changes/341.added new file mode 100644 index 00000000..3a5de857 --- /dev/null +++ b/changes/341.added @@ -0,0 +1 @@ +Added a "grafana disabled" view in case a user clicks on a grafana nav menu item when the grafana integration is disabled. diff --git a/changes/341.fixed b/changes/341.fixed new file mode 100644 index 00000000..adf56166 --- /dev/null +++ b/changes/341.fixed @@ -0,0 +1,4 @@ +Fixed django-constance not being upgradable due to this app accessing the database before migrations could run. +Removed conditional logic for adding grafana navigation menu items. +Fixed Nautobot v2.3 incompatibility caused by saved views not being able to determine the models' table classes. +Added exception handling for cases where diffsync is not installed, since it's marked as optional. diff --git a/changes/341.housekeeping b/changes/341.housekeeping new file mode 100644 index 00000000..c694cc1c --- /dev/null +++ b/changes/341.housekeeping @@ -0,0 +1 @@ +Fixed dev environment nautobot_config.py to fall back to constance if environment variable is not used. diff --git a/changes/341.removed b/changes/341.removed new file mode 100644 index 00000000..d31260be --- /dev/null +++ b/changes/341.removed @@ -0,0 +1 @@ +Removed all grafana integration API files since there we no API views provided by grafana integration. diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 31cc69c5..f38be8ce 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -146,36 +146,29 @@ # | `session_cache_timeout` | Controls session cache | No | `86400` | # = Chat Platforms =================== # - Mattermost ----------------------- - "enable_mattermost": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MATTERMOST")), "mattermost_api_token": os.environ.get("MATTERMOST_API_TOKEN"), "mattermost_url": os.environ.get("MATTERMOST_URL"), # - Microsoft Teams ------------------ - "enable_ms_teams": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MS_TEAMS")), "microsoft_app_id": os.environ.get("MICROSOFT_APP_ID"), "microsoft_app_password": os.environ.get("MICROSOFT_APP_PASSWORD"), # - Slack ---------------------------- - "enable_slack": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_SLACK")), "slack_api_token": os.environ.get("SLACK_API_TOKEN"), "slack_app_token": os.environ.get("SLACK_APP_TOKEN"), "slack_signing_secret": os.environ.get("SLACK_SIGNING_SECRET"), "slack_slash_command_prefix": os.environ.get("SLACK_SLASH_COMMAND_PREFIX", "/"), # - Cisco Webex ---------------------- - "enable_webex": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_WEBEX")), "webex_msg_char_limit": int(os.getenv("WEBEX_MSG_CHAR_LIMIT", "7439")), "webex_signing_secret": os.environ.get("WEBEX_SIGNING_SECRET"), "webex_token": os.environ.get("WEBEX_ACCESS_TOKEN"), # = Integrations ===================== # - Cisco ACI ------------------------ - "enable_aci": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ACI")), "aci_creds": {x: os.environ[x] for x in os.environ if "APIC" in x}, # - AWX / Ansible Tower -------------- - "enable_ansible": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ANSIBLE")), "tower_password": os.getenv("NAUTOBOT_TOWER_PASSWORD"), "tower_uri": os.getenv("NAUTOBOT_TOWER_URI"), "tower_username": os.getenv("NAUTOBOT_TOWER_USERNAME"), "tower_verify_ssl": is_truthy(os.getenv("NAUTOBOT_TOWER_VERIFY_SSL", "true")), # - Arista CloudVision --------------- - "enable_aristacv": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ARISTACV")), "aristacv_cvaas_url": os.environ.get("ARISTACV_CVAAS_URL"), "aristacv_cvaas_token": os.environ.get("ARISTACV_CVAAS_TOKEN"), "aristacv_cvp_host": os.environ.get("ARISTACV_CVP_HOST"), @@ -184,7 +177,6 @@ "aristacv_cvp_username": os.environ.get("ARISTACV_CVP_USERNAME"), "aristacv_on_prem": is_truthy(os.environ.get("ARISTACV_ON_PREM")), # - Grafana -------------------------- - "enable_grafana": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_GRAFANA")), "grafana_url": os.environ.get("GRAFANA_URL", ""), "grafana_api_key": os.environ.get("GRAFANA_API_KEY", ""), "grafana_default_width": 0, @@ -194,26 +186,48 @@ "grafana_org_id": 1, "grafana_default_tz": "America/Denver", # - IPFabric -------------------------- - "enable_ipfabric": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_IPFABRIC")), "ipfabric_api_token": os.environ.get("IPFABRIC_API_TOKEN"), "ipfabric_host": os.environ.get("IPFABRIC_HOST"), "ipfabric_timeout": os.environ.get("IPFABRIC_TIMEOUT", 15), "ipfabric_verify": is_truthy(os.environ.get("IPFABRIC_VERIFY", True)), # - Cisco Meraki --------------------- - "enable_meraki": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MERAKI")), "meraki_dashboard_api_key": os.environ.get("MERAKI_API_KEY"), # - Palo Alto Panorama --------------- - "enable_panorama": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_PANORAMA")), "panorama_host": os.environ.get("PANORAMA_HOST"), "panorama_password": os.environ.get("PANORAMA_PASSWORD"), "panorama_user": os.environ.get("PANORAMA_USER"), # - Cisco NSO ------------------------ - "enable_nso": is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_NSO")), "nso_url": os.environ.get("NSO_URL"), "nso_username": os.environ.get("NSO_USERNAME"), "nso_password": os.environ.get("NSO_PASSWORD"), "nso_request_timeout": os.environ.get("NSO_REQUEST_TIMEOUT", 60), }, } +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_MATTERMOST", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_mattermost"] = ( + is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MATTERMOST")), + ) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_MS_TEAMS", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_ms_teams"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MS_TEAMS")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_SLACK", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_slack"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_SLACK")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_WEBEX", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_webex"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_WEBEX")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_ACI", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_aci"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ACI")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_ANSIBLE", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_ansible"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ANSIBLE")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_ARISTACV", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_aristacv"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_ARISTACV")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_GRAFANA", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_grafana"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_GRAFANA")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_IPFABRIC", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_ipfabric"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_IPFABRIC")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_MERAKI", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_meraki"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_MERAKI")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_PANORAMA", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_panorama"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_PANORAMA")) +if os.getenv("NAUTOBOT_CHATOPS_ENABLE_NSO", "") != "": + PLUGINS_CONFIG["nautobot_chatops"]["enable_nso"] = is_truthy(os.getenv("NAUTOBOT_CHATOPS_ENABLE_NSO")) METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_METRICS_ENABLED")) diff --git a/nautobot_chatops/api/urls.py b/nautobot_chatops/api/urls.py index f470beb1..eece0127 100644 --- a/nautobot_chatops/api/urls.py +++ b/nautobot_chatops/api/urls.py @@ -2,9 +2,8 @@ import logging -from django.urls import include, path +from django.urls import path from nautobot.apps.api import OrderedDefaultRouter -from nautobot.apps.config import get_app_settings_or_config from nautobot_chatops.api.views.generic import ( AccessGrantViewSet, @@ -13,44 +12,24 @@ NautobotChatopsRootView, ) from nautobot_chatops.api.views.lookup import AccessLookupView, UserEmailLookupView +from nautobot_chatops.api.views.mattermost import MattermostInteractionView, MattermostSlashCommandView +from nautobot_chatops.api.views.ms_teams import MSTeamsMessagesView +from nautobot_chatops.api.views.slack import SlackEventAPIView, SlackInteractionView, SlackSlashCommandView +from nautobot_chatops.api.views.webex import WebexView logger = logging.getLogger(__name__) urlpatterns = [ path("lookup/", AccessLookupView.as_view(), name="access_lookup"), path("email-lookup/", UserEmailLookupView.as_view(), name="email_lookup"), + path("slack/slash_command/", SlackSlashCommandView.as_view(), name="slack_slash_command"), + path("slack/interaction/", SlackInteractionView.as_view(), name="slack_interaction"), + path("slack/event/", SlackEventAPIView.as_view(), name="slack_event"), + path("ms_teams/messages/", MSTeamsMessagesView.as_view(), name="ms_teams_messages"), + path("webex/", WebexView.as_view(), name="webex"), + path("mattermost/slash_command/", MattermostSlashCommandView.as_view(), name="mattermost_slash_command"), + path("mattermost/interaction/", MattermostInteractionView.as_view(), name="mattermost_interaction"), ] -if get_app_settings_or_config("nautobot_chatops", "enable_slack"): - from nautobot_chatops.api.views.slack import SlackEventAPIView, SlackInteractionView, SlackSlashCommandView - - urlpatterns += [ - path("slack/slash_command/", SlackSlashCommandView.as_view(), name="slack_slash_command"), - path("slack/interaction/", SlackInteractionView.as_view(), name="slack_interaction"), - path("slack/event/", SlackEventAPIView.as_view(), name="slack_event"), - ] - -if get_app_settings_or_config("nautobot_chatops", "enable_ms_teams"): - from nautobot_chatops.api.views.ms_teams import MSTeamsMessagesView - - urlpatterns += [ - path("ms_teams/messages/", MSTeamsMessagesView.as_view(), name="ms_teams_messages"), - ] - -if get_app_settings_or_config("nautobot_chatops", "enable_webex"): - from nautobot_chatops.api.views.webex import WebexView - - urlpatterns += [ - path("webex/", WebexView.as_view(), name="webex"), - ] - -if get_app_settings_or_config("nautobot_chatops", "enable_mattermost"): - from nautobot_chatops.api.views.mattermost import MattermostInteractionView, MattermostSlashCommandView - - urlpatterns += [ - path("mattermost/slash_command/", MattermostSlashCommandView.as_view(), name="mattermost_slash_command"), - path("mattermost/interaction/", MattermostInteractionView.as_view(), name="mattermost_interaction"), - ] - router = OrderedDefaultRouter() router.APIRootView = NautobotChatopsRootView router.register("commandtoken", CommandTokenViewSet) @@ -60,5 +39,3 @@ app_name = "nautobot_chatops-api" urlpatterns += router.urls - -urlpatterns += [path("grafana/", include("nautobot_chatops.integrations.grafana.api.urls"))] diff --git a/nautobot_chatops/api/views/mattermost.py b/nautobot_chatops/api/views/mattermost.py index 25e0013f..a05b827e 100644 --- a/nautobot_chatops/api/views/mattermost.py +++ b/nautobot_chatops/api/views/mattermost.py @@ -15,6 +15,7 @@ from nautobot_chatops.metrics import signature_error_cntr from nautobot_chatops.models import CommandToken from nautobot_chatops.utils import check_and_enqueue_command +from nautobot_chatops.views import SettingsControlledViewMixin from nautobot_chatops.workers import commands_help, get_commands_registry, parse_command_string # pylint: disable=logging-fstring-interpolation @@ -67,8 +68,14 @@ def verify_signature(request): return True, "Signature is valid" +class MattermostView(SettingsControlledViewMixin, View): + """Base class for Mattermost views.""" + + enable_view_setting = "enable_mattermost" + + @method_decorator(csrf_exempt, name="dispatch") -class MattermostSlashCommandView(View): +class MattermostSlashCommandView(MattermostView): """Handle notifications from a Mattermost /command.""" http_method_names = ["post"] @@ -117,7 +124,7 @@ def post(self, request, *args, **kwargs): @method_decorator(csrf_exempt, name="dispatch") -class MattermostInteractionView(View): +class MattermostInteractionView(MattermostView): """Handle notifications resulting from a Mattermost interactive block.""" http_method_names = ["post"] diff --git a/nautobot_chatops/api/views/ms_teams.py b/nautobot_chatops/api/views/ms_teams.py index 6b95a3b3..9fb42b87 100644 --- a/nautobot_chatops/api/views/ms_teams.py +++ b/nautobot_chatops/api/views/ms_teams.py @@ -14,6 +14,7 @@ from nautobot_chatops.dispatchers.ms_teams import MSTeamsDispatcher from nautobot_chatops.utils import check_and_enqueue_command +from nautobot_chatops.views import SettingsControlledViewMixin from nautobot_chatops.workers import commands_help, get_commands_registry, parse_command_string logger = logging.getLogger(__name__) @@ -113,9 +114,10 @@ def verify_jwt_token(request_headers, request_json): @method_decorator(csrf_exempt, name="dispatch") -class MSTeamsMessagesView(View): +class MSTeamsMessagesView(SettingsControlledViewMixin, View): """Handle notifications from a Microsoft Teams bot.""" + enable_view_setting = "enable_ms_teams" http_method_names = ["post"] # pylint: disable=too-many-locals,too-many-branches,too-many-statements diff --git a/nautobot_chatops/api/views/slack.py b/nautobot_chatops/api/views/slack.py index b390e4b6..93c4e3cc 100644 --- a/nautobot_chatops/api/views/slack.py +++ b/nautobot_chatops/api/views/slack.py @@ -16,6 +16,7 @@ from nautobot_chatops.dispatchers.slack import SlackDispatcher from nautobot_chatops.metrics import signature_error_cntr from nautobot_chatops.utils import check_and_enqueue_command +from nautobot_chatops.views import SettingsControlledViewMixin from nautobot_chatops.workers import commands_help, get_commands_registry, parse_command_string # pylint: disable=logging-fstring-interpolation @@ -65,8 +66,14 @@ def verify_signature(request): return True, "Signature is valid" +class SlackView(SettingsControlledViewMixin, View): + """Base class for Slack views.""" + + enable_view_setting = "enable_slack" + + @method_decorator(csrf_exempt, name="dispatch") -class SlackSlashCommandView(View): +class SlackSlashCommandView(SlackView): """Handle notifications from a Slack /command.""" http_method_names = ["post"] @@ -115,7 +122,7 @@ def post(self, request, *args, **kwargs): @method_decorator(csrf_exempt, name="dispatch") -class SlackInteractionView(View): +class SlackInteractionView(SlackView): """Handle notifications resulting from a Slack interactive block or modal.""" http_method_names = ["post"] @@ -276,7 +283,7 @@ def post(self, request, *args, **kwargs): @method_decorator(csrf_exempt, name="dispatch") -class SlackEventAPIView(View): +class SlackEventAPIView(SlackView): """Handle notifications resulting from a mention of the Slack app.""" http_method_names = ["post"] diff --git a/nautobot_chatops/api/views/webex.py b/nautobot_chatops/api/views/webex.py index bf8e7b5d..ed003f76 100644 --- a/nautobot_chatops/api/views/webex.py +++ b/nautobot_chatops/api/views/webex.py @@ -16,6 +16,7 @@ from nautobot_chatops.dispatchers.webex import WEBEX_CONFIG, WebexDispatcher from nautobot_chatops.utils import check_and_enqueue_command +from nautobot_chatops.views import SettingsControlledViewMixin from nautobot_chatops.workers import commands_help, get_commands_registry, parse_command_string logger = logging.getLogger(__name__) @@ -76,9 +77,10 @@ def verify_signature(request): @method_decorator(csrf_exempt, name="dispatch") -class WebexView(View): +class WebexView(SettingsControlledViewMixin, View): """Handle all supported inbound notifications from Webex.""" + enable_view_setting = "enable_webex" http_method_names = ["post"] # pylint: disable=too-many-locals,too-many-return-statements,too-many-branches diff --git a/nautobot_chatops/integrations/grafana/api/__init__.py b/nautobot_chatops/integrations/grafana/api/__init__.py deleted file mode 100644 index 590bacd3..00000000 --- a/nautobot_chatops/integrations/grafana/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Base module for nautobot_chatops.integrations.grafana Provider.""" diff --git a/nautobot_chatops/integrations/grafana/api/urls.py b/nautobot_chatops/integrations/grafana/api/urls.py deleted file mode 100644 index ef337c21..00000000 --- a/nautobot_chatops/integrations/grafana/api/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Django urlpatterns declaration for nautobot_chatops.integrations.grafana app.""" - -from nautobot.apps.api import OrderedDefaultRouter -from nautobot.apps.config import get_app_settings_or_config - -from nautobot_chatops.integrations.grafana.api.views.generic import NautobotPluginChatopsGrafanaRootView - -urlpatterns = [] -if get_app_settings_or_config("nautobot_chatops", "enable_grafana"): - router = OrderedDefaultRouter() - router.APIRootView = NautobotPluginChatopsGrafanaRootView - - app_name = "nautobot_chatops.grafana-api" - - urlpatterns += router.urls diff --git a/nautobot_chatops/integrations/grafana/api/views/__init__.py b/nautobot_chatops/integrations/grafana/api/views/__init__.py deleted file mode 100644 index 752d6639..00000000 --- a/nautobot_chatops/integrations/grafana/api/views/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""API Views module for the nautobot_chatops.integrations.grafana Nautobot App. - -The views implemented in this module act as endpoints for various chat platforms -to send requests and notifications to. -""" diff --git a/nautobot_chatops/integrations/grafana/api/views/generic.py b/nautobot_chatops/integrations/grafana/api/views/generic.py deleted file mode 100644 index 62d47b05..00000000 --- a/nautobot_chatops/integrations/grafana/api/views/generic.py +++ /dev/null @@ -1,11 +0,0 @@ -"""API Views for Nautobot App Chatops Grafana.""" - -from rest_framework.routers import APIRootView - - -class NautobotPluginChatopsGrafanaRootView(APIRootView): - """Nautobot Chatops Grafana API root view.""" - - def get_view_name(self): - """Return name for API Root.""" - return "Grafana" diff --git a/nautobot_chatops/integrations/grafana/diffsync/sync.py b/nautobot_chatops/integrations/grafana/diffsync/sync.py index b7b00149..c69a7c0b 100644 --- a/nautobot_chatops/integrations/grafana/diffsync/sync.py +++ b/nautobot_chatops/integrations/grafana/diffsync/sync.py @@ -2,16 +2,22 @@ from typing import Union -from diffsync import DiffSyncFlags - -from nautobot_chatops.integrations.grafana.diffsync.models import ( - GrafanaDashboard, - GrafanaPanel, - GrafanaVariable, - NautobotDashboard, - NautobotPanel, - NautobotVariable, -) +try: + from diffsync import DiffSyncFlags + + DIFFSYNC_INSTALLED = True +except ImportError: + DIFFSYNC_INSTALLED = False + +if DIFFSYNC_INSTALLED: + from nautobot_chatops.integrations.grafana.diffsync.models import ( + GrafanaDashboard, + GrafanaPanel, + GrafanaVariable, + NautobotDashboard, + NautobotPanel, + NautobotVariable, + ) from nautobot_chatops.integrations.grafana.grafana import handler from nautobot_chatops.integrations.grafana.models import Dashboard, Panel, PanelVariable @@ -21,7 +27,13 @@ def run_dashboard_sync(overwrite: bool = False) -> Union[str, None]: Args: overwrite (bool): Overwrite Nautobot data and delete records that are no longer in Grafana. + + Raises: + ImportError: If DiffSync is not installed. """ + if not DIFFSYNC_INSTALLED: + raise ImportError("DiffSync is not installed. Please install DiffSync to use the grafana integration.") + df_flags = DiffSyncFlags.NONE if overwrite else DiffSyncFlags.SKIP_UNMATCHED_DST # Fetch dashboards from the Grafana API @@ -51,7 +63,13 @@ def run_panels_sync(dashboard: Dashboard, overwrite: bool = False) -> Union[str, Args: dashboard (nautobot_chatops.integrations.grafana.models.Dashboard): The dashboard we are going to do a diffsync with. overwrite (bool): Overwrite Nautobot data and delete records that are no longer in Grafana. + + Raises: + ImportError: If DiffSync is not installed. """ + if not DIFFSYNC_INSTALLED: + raise ImportError("DiffSync is not installed. Please install DiffSync to use the grafana integration.") + df_flags = DiffSyncFlags.NONE if overwrite else DiffSyncFlags.SKIP_UNMATCHED_DST # Fetch panels from the Grafana API @@ -81,7 +99,13 @@ def run_variables_sync(dashboard: Dashboard, overwrite: bool = False) -> Union[s Args: dashboard (nautobot_chatops.integrations.grafana.models.Dashboard): The dashboard we are going to do a diffsync with. overwrite (bool): Overwrite Nautobot data and delete records that are no longer in Grafana. + + Raises: + ImportError: If DiffSync is not installed. """ + if not DIFFSYNC_INSTALLED: + raise ImportError("DiffSync is not installed. Please install DiffSync to use the grafana integration.") + df_flags = DiffSyncFlags.NONE if overwrite else DiffSyncFlags.SKIP_UNMATCHED_DST # Fetch panels from the Grafana API diff --git a/nautobot_chatops/integrations/grafana/navigation.py b/nautobot_chatops/integrations/grafana/navigation.py index 922fbf3a..22ce676e 100644 --- a/nautobot_chatops/integrations/grafana/navigation.py +++ b/nautobot_chatops/integrations/grafana/navigation.py @@ -4,7 +4,7 @@ items = [ NavMenuItem( - link="plugins:nautobot_chatops:grafanadashboards", + link="plugins:nautobot_chatops:grafanadashboard_list", permissions=["nautobot_chatops.dashboards_read"], name="Grafana Dashboards", buttons=( @@ -15,7 +15,7 @@ ), ), NavMenuItem( - link="plugins:nautobot_chatops:grafanapanel", + link="plugins:nautobot_chatops:grafanapanel_list", permissions=["nautobot_chatops.panel_read"], name="Grafana Panels", buttons=( @@ -26,7 +26,7 @@ ), ), NavMenuItem( - link="plugins:nautobot_chatops:grafanapanelvariables", + link="plugins:nautobot_chatops:grafanapanelvariable_list", permissions=["nautobot_chatops.panelvariables_read"], name="Grafana Variables", buttons=( diff --git a/nautobot_chatops/integrations/grafana/tables.py b/nautobot_chatops/integrations/grafana/tables.py index 9e3dfa8f..72f4e7d7 100644 --- a/nautobot_chatops/integrations/grafana/tables.py +++ b/nautobot_chatops/integrations/grafana/tables.py @@ -3,29 +3,29 @@ from django_tables2 import BooleanColumn, Column, TemplateColumn from nautobot.core.tables import BaseTable, ButtonsColumn, ToggleColumn -from nautobot_chatops.integrations.grafana.models import Dashboard, Panel, PanelVariable +from nautobot_chatops.integrations.grafana.models import GrafanaDashboard, GrafanaPanel, GrafanaPanelVariable -class DashboardViewTable(BaseTable): # pylint: disable=nb-sub-class-name +class GrafanaDashboardTable(BaseTable): # pylint: disable=nb-sub-class-name """Table for rendering panels for dashboards in the grafana app.""" pk = ToggleColumn() - actions = ButtonsColumn(Dashboard, buttons=("changelog", "edit", "delete")) + actions = ButtonsColumn(GrafanaDashboard, buttons=("changelog", "edit", "delete")) class Meta(BaseTable.Meta): # pylint: disable=too-few-public-methods """Meta for class DashboardViewTable.""" - model = Dashboard + model = GrafanaDashboard fields = ("pk", "dashboard_slug", "dashboard_uid", "friendly_name", "actions") -class PanelViewTable(BaseTable): # pylint: disable=nb-sub-class-name +class GrafanaPanelTable(BaseTable): # pylint: disable=nb-sub-class-name """Table for rendering panels for dashboards in the grafana app.""" pk = ToggleColumn() - actions = ButtonsColumn(Panel, buttons=("changelog", "edit", "delete")) + actions = ButtonsColumn(GrafanaPanel, buttons=("changelog", "edit", "delete")) chat_command = TemplateColumn( template_code="/grafana get-{{ record.command_name }}", @@ -36,16 +36,16 @@ class PanelViewTable(BaseTable): # pylint: disable=nb-sub-class-name class Meta(BaseTable.Meta): # pylint: disable=too-few-public-methods """Meta for class PanelViewTable.""" - model = Panel + model = GrafanaPanel fields = ("pk", "chat_command", "command_name", "friendly_name", "panel_id", "dashboard", "active", "actions") -class PanelVariableViewTable(BaseTable): # pylint: disable=nb-sub-class-name +class GrafanaPanelVariableTable(BaseTable): # pylint: disable=nb-sub-class-name """Table for rendering panel variables for dashboards in the grafana app.""" pk = ToggleColumn() - actions = ButtonsColumn(PanelVariable, buttons=("changelog", "edit", "delete")) + actions = ButtonsColumn(GrafanaPanelVariable, buttons=("changelog", "edit", "delete")) value = TemplateColumn( template_code=( "{% if record.value %}
{{ record.value }}{% else %}{{ record.value}}{% endif %}" @@ -58,7 +58,7 @@ class PanelVariableViewTable(BaseTable): # pylint: disable=nb-sub-class-name class Meta(BaseTable.Meta): # pylint: disable=too-few-public-methods """Meta for class PanelVariableViewTable.""" - model = PanelVariable + model = GrafanaPanelVariable fields = [ "pk", "panel", diff --git a/nautobot_chatops/integrations/grafana/urls.py b/nautobot_chatops/integrations/grafana/urls.py index 65a44008..ed237652 100644 --- a/nautobot_chatops/integrations/grafana/urls.py +++ b/nautobot_chatops/integrations/grafana/urls.py @@ -3,7 +3,7 @@ from django.urls import path from nautobot.extras.views import ObjectChangeLogView -from nautobot_chatops.integrations.grafana.models import Dashboard, Panel, PanelVariable +from nautobot_chatops.integrations.grafana.models import GrafanaDashboard, GrafanaPanel, GrafanaPanelVariable from nautobot_chatops.integrations.grafana.views import ( DashboardBulkEditView, Dashboards, @@ -33,12 +33,12 @@ urlpatterns = [ # Dashboard specific views. - path("grafana/dashboards/", Dashboards.as_view(), name="grafanadashboards"), + path("grafana/dashboards/", Dashboards.as_view(), name="grafanadashboard_list"), path( "dashboards/
+ The Grafana integration is currently disabled. Please contact your administrator for more information. +
+