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

feat: add Google Drive and Maxmind healthchecks #380

Merged
merged 1 commit into from
Jan 24, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/integrations/google_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,15 @@ def update_spreadsheet_close_incident(channel_name):
).execute()
return True
return False


def healthcheck():
"""Check if the bot can interact with Google Drive."""
healthy = False
try:
metadata = list_metadata(INCIDENT_TEMPLATE)
healthy = "id" in metadata
logging.info(f"Google Drive healthcheck result: {metadata}")
except Exception as error:
logging.error(f"Google Drive healthcheck failed: {error}")
return healthy
13 changes: 13 additions & 0 deletions app/integrations/maxmind.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import geoip2.database
from geoip2.errors import AddressNotFoundError

Expand All @@ -16,3 +17,15 @@ def geolocate(ip):
return "IP address not found"
except ValueError:
return "Invalid IP address"


def healthcheck():
"""Check if the bot can interact with Maxmind."""
healthy = False
try:
result = geolocate("8.8.8.8")
Copy link
Member Author

@patheard patheard Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions for different IP addresses to use for this health check, but my thinking was that if Google public DNS isn't working, things are dire.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha, I agree! I think this one would be the safest one to use.

healthy = isinstance(result, tuple)
logging.info(f"Maxmind healthcheck result: {result}")
except Exception as error:
logging.error(f"Maxmind healthcheck failed: {error}")
return healthy
4 changes: 3 additions & 1 deletion app/jobs/scheduled_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import schedule
import logging

from integrations import opsgenie
from integrations import google_drive, maxmind, opsgenie

logging.basicConfig(level=logging.INFO)

Expand All @@ -29,6 +29,8 @@ def scheduler_heartbeat():
def integration_healthchecks():
logging.info("Running integration healthchecks ...")
healthchecks = {
"google_drive": google_drive.healthcheck,
"maxmind": maxmind.healthcheck,
"opsgenie": opsgenie.healthcheck,
}
for key, healthcheck in healthchecks.items():
Expand Down
12 changes: 12 additions & 0 deletions app/tests/intergrations/test_google_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,15 @@ def test_update_spreadsheet(get_google_service_mock):

# assert that the function returns the correct response
assert google_drive.update_spreadsheet_close_incident(channel_name) is True


@patch("integrations.google_drive.list_metadata")
def test_healthcheck_healthy(mock_list_metadata):
mock_list_metadata.return_value = {"id": "test_doc"}
assert google_drive.healthcheck() is True


@patch("integrations.google_drive.list_metadata")
def test_healthcheck_unhealthy(mock_list_metadata):
mock_list_metadata.return_value = None
assert google_drive.healthcheck() is False
15 changes: 15 additions & 0 deletions app/tests/intergrations/test_maxmind.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,18 @@ def test_geolocate_not_found(geiop2_mock):
def test_geolocate_invalid_ip(geiop2_mock):
geiop2_mock.database.Reader().city.side_effect = ValueError
assert maxmind.geolocate("test_ip") == "Invalid IP address"


@patch("integrations.maxmind.geoip2")
def test_healthcheck_healthy(geiop2_mock):
geiop2_mock.database.Reader().city.return_value.country.iso_code = "CA"
geiop2_mock.database.Reader().city.return_value.city.name = "test_city"
geiop2_mock.database.Reader().city.return_value.location.latitude = "test_lat"
geiop2_mock.database.Reader().city.return_value.location.longitude = "test_long"
assert maxmind.healthcheck() is True


@patch("integrations.maxmind.geoip2")
def test_healthcheck_unhealthy(geiop2_mock):
geiop2_mock.database.Reader().city.side_effect = ValueError
assert maxmind.healthcheck() is False
25 changes: 20 additions & 5 deletions app/tests/jobs/test_scheduled_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,35 @@ def test_run_continuously(time_mock, threading_mock, schedule_mock):
assert result == cease_continuous_run


@patch("jobs.scheduled_tasks.google_drive")
@patch("jobs.scheduled_tasks.maxmind")
@patch("jobs.scheduled_tasks.opsgenie")
@patch("jobs.scheduled_tasks.logging")
def test_integration_healthchecks_healthy(mock_logging, mock_opsgenie):
def test_integration_healthchecks_healthy(
mock_logging, mock_opsgenie, mock_maxmind, mock_google_drive
):
mock_google_drive.healthcheck.return_value = True
mock_maxmind.healthcheck.return_value = True
mock_opsgenie.healthcheck.return_value = True
scheduled_tasks.integration_healthchecks()
assert mock_google_drive.healthcheck.call_count == 1
assert mock_maxmind.healthcheck.call_count == 1
assert mock_opsgenie.healthcheck.call_count == 1
assert mock_logging.error.call_count == 0


@patch("jobs.scheduled_tasks.google_drive")
@patch("jobs.scheduled_tasks.maxmind")
@patch("jobs.scheduled_tasks.opsgenie")
@patch("jobs.scheduled_tasks.logging")
def test_integration_healthchecks_unhealthy(mock_logging, mock_opsgenie):
mock_opsgenie.healthcheck.return_value = False
mock_opsgenie.healthcheck.__name__ = "test_integration"
def test_integration_healthchecks_unhealthy(
mock_logging, mock_opsgenie, mock_maxmind, mock_google_drive
):
mock_google_drive.healthcheck.return_value = False
mock_maxmind.healthcheck.return_value = False
mock_opsgenie.healthcheck.return_value = True
scheduled_tasks.integration_healthchecks()
assert mock_google_drive.healthcheck.call_count == 1
assert mock_maxmind.healthcheck.call_count == 1
assert mock_opsgenie.healthcheck.call_count == 1
assert mock_logging.error.call_count == 1
assert mock_logging.error.call_count == 2
Loading