Skip to content

Commit

Permalink
Fix constance being accessed before database is ready and other fixes (
Browse files Browse the repository at this point in the history
  • Loading branch information
gsnider2195 authored Nov 15, 2024
1 parent 757ed3e commit 4761790
Show file tree
Hide file tree
Showing 26 changed files with 304 additions and 228 deletions.
1 change: 1 addition & 0 deletions changes/341.added
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 4 additions & 0 deletions changes/341.fixed
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions changes/341.housekeeping
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed dev environment nautobot_config.py to fall back to constance if environment variable is not used.
1 change: 1 addition & 0 deletions changes/341.removed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed all grafana integration API files since there we no API views provided by grafana integration.
38 changes: 26 additions & 12 deletions development/nautobot_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -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,
Expand All @@ -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"))
47 changes: 12 additions & 35 deletions nautobot_chatops/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -60,5 +39,3 @@
app_name = "nautobot_chatops-api"

urlpatterns += router.urls

urlpatterns += [path("grafana/", include("nautobot_chatops.integrations.grafana.api.urls"))]
11 changes: 9 additions & 2 deletions nautobot_chatops/api/views/mattermost.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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"]
Expand Down
4 changes: 3 additions & 1 deletion nautobot_chatops/api/views/ms_teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions nautobot_chatops/api/views/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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"]
Expand Down
4 changes: 3 additions & 1 deletion nautobot_chatops/api/views/webex.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion nautobot_chatops/integrations/grafana/api/__init__.py

This file was deleted.

15 changes: 0 additions & 15 deletions nautobot_chatops/integrations/grafana/api/urls.py

This file was deleted.

5 changes: 0 additions & 5 deletions nautobot_chatops/integrations/grafana/api/views/__init__.py

This file was deleted.

11 changes: 0 additions & 11 deletions nautobot_chatops/integrations/grafana/api/views/generic.py

This file was deleted.

Loading

0 comments on commit 4761790

Please sign in to comment.