Skip to content

Commit

Permalink
feat: Preliminary version of Waffle config watcher
Browse files Browse the repository at this point in the history
This still needs to be hooked up to Slack.

- New app `edx_arch_experiments.config_watcher.ConfigWatcher`
- New dependency on django-waffle
- Dependency upgrade
  • Loading branch information
timmc-edx committed Oct 23, 2023
1 parent 1cc25f5 commit fe6e73e
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Unreleased
~~~~~~~~~~
* Add script to get github action errors
* Add script to republish failed events
* Add ``edx_arch_experiments.config_watcher`` Django app for monitoring Waffle changes

[2.1.0] - 2023-10-10
~~~~~~~~~~~~~~~~~~~~
Expand Down
Empty file.
16 changes: 16 additions & 0 deletions edx_arch_experiments/config_watcher/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
App for reporting configuration changes to Slack for operational awareness.
"""

from django.apps import AppConfig

class ConfigWatcherApp(AppConfig):
"""
Django application to report configuration changes to operators.
"""
name = 'edx_arch_experiments.config_watcher'

def ready(self):
from .signals import receivers # pylint: disable=import-outside-toplevel

receivers.connect_receivers()
Empty file.
65 changes: 65 additions & 0 deletions edx_arch_experiments/config_watcher/signals/receivers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Signal receivers for the config watcher.
Call ``connect_receivers`` to initialize.
"""

import waffle.models
from django.db.models import signals
from django.dispatch import receiver


def _report_waffle_change(model_short_name, instance, created, fields):
verb = "created" if created else "updated"
state_desc = ", ".join(f"{field}={repr(getattr(instance, field))}" for field in fields)
print(f"⚡⚡⚡ Waffle {model_short_name} {instance.name!r} was {verb}. New config: {state_desc}")


def _report_waffle_delete(model_short_name, instance):
print(f"💥💥💥 Waffle {model_short_name} {instance.name!r} was deleted")


_WAFFLE_MODELS_TO_OBSERVE = [
{
'model': waffle.models.Flag,
'short_name': 'flag',
'fields': ['everyone', 'percent', 'superusers', 'staff', 'authenticated', 'note', 'languages'],
},
{
'model': waffle.models.Switch,
'short_name': 'switch',
'fields': ['active', 'note'],
},
{
'model': waffle.models.Sample,
'short_name': 'sample',
'fields': ['percent', 'note'],
},
]


def _register_waffle_observation(*, model, short_name, fields):
"""
Register a Waffle model for observation.
Args:
model (class): The model class to monitor
short_name (str): A short descriptive name for an instance of the model, e.g. "flag"
fields (list): Names of fields to report on in the Slack message
"""
@receiver(signals.post_save, sender=model)
def log_waffle_change(*args, instance, created, **kwargs):
_report_waffle_change(short_name, instance, created, fields)

@receiver(signals.post_delete, sender=model)
def log_waffle_change(*args, instance, **kwargs):
_report_waffle_delete(short_name, instance)


def connect_receivers():
"""
Initialize application's receivers.
"""
for config in _WAFFLE_MODELS_TO_OBSERVE:
# Pass config to function to capture value properly.
_register_waffle_observation(**config)
1 change: 1 addition & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

Django # Web application framework
edx_django_utils
django-waffle # Configuration switches and flags -- used by config_watcher app
8 changes: 5 additions & 3 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ django==3.2.22
django-crum==0.7.9
# via edx-django-utils
django-waffle==4.0.0
# via edx-django-utils
# via
# -r requirements/base.in
# edx-django-utils
edx-django-utils==5.7.0
# via -r requirements/base.in
newrelic==9.1.0
newrelic==9.1.1
# via edx-django-utils
pbr==5.11.1
# via stevedore
psutil==5.9.5
psutil==5.9.6
# via edx-django-utils
pycparser==2.21
# via cffi
Expand Down
27 changes: 10 additions & 17 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ asgiref==3.7.2
# via
# -r requirements/quality.txt
# django
astroid==2.15.8
astroid==3.0.1
# via
# -r requirements/quality.txt
# pylint
Expand All @@ -28,7 +28,7 @@ cffi==1.16.0
# pynacl
chardet==5.2.0
# via diff-cover
charset-normalizer==3.3.0
charset-normalizer==3.3.1
# via
# -r requirements/quality.txt
# requests
Expand All @@ -52,12 +52,13 @@ code-annotations==1.5.0
coverage[toml]==7.3.2
# via
# -r requirements/quality.txt
# coverage
# pytest-cov
cryptography==41.0.4
# via
# -r requirements/quality.txt
# secretstorage
diff-cover==7.7.0
diff-cover==8.0.0
# via -r requirements/dev.in
dill==0.3.7
# via
Expand Down Expand Up @@ -143,10 +144,6 @@ keyring==24.2.0
# via
# -r requirements/quality.txt
# twine
lazy-object-proxy==1.9.0
# via
# -r requirements/quality.txt
# astroid
lxml==4.9.3
# via edx-i18n-tools
markdown-it-py==3.0.0
Expand All @@ -169,7 +166,7 @@ more-itertools==10.1.0
# via
# -r requirements/quality.txt
# jaraco-classes
newrelic==9.1.0
newrelic==9.1.1
# via
# -r requirements/quality.txt
# edx-django-utils
Expand Down Expand Up @@ -212,15 +209,15 @@ pluggy==1.3.0
# tox
polib==1.2.0
# via edx-i18n-tools
psutil==5.9.5
psutil==5.9.6
# via
# -r requirements/quality.txt
# edx-django-utils
py==1.11.0
# via
# -r requirements/ci.txt
# tox
pycodestyle==2.11.0
pycodestyle==2.11.1
# via -r requirements/quality.txt
pycparser==2.21
# via
Expand All @@ -234,7 +231,7 @@ pygments==2.16.1
# diff-cover
# readme-renderer
# rich
pylint==2.17.7
pylint==3.0.2
# via
# -r requirements/quality.txt
# edx-lint
Expand All @@ -245,7 +242,7 @@ pylint-celery==0.3
# via
# -r requirements/quality.txt
# edx-lint
pylint-django==2.5.3
pylint-django==2.5.5
# via
# -r requirements/quality.txt
# edx-lint
Expand Down Expand Up @@ -364,7 +361,7 @@ typing-extensions==4.8.0
# astroid
# pylint
# rich
urllib3==2.0.6
urllib3==2.0.7
# via
# -r requirements/quality.txt
# requests
Expand All @@ -377,10 +374,6 @@ wheel==0.41.2
# via
# -r requirements/pip-tools.txt
# pip-tools
wrapt==1.15.0
# via
# -r requirements/quality.txt
# astroid
zipp==3.17.0
# via
# -r requirements/pip-tools.txt
Expand Down
9 changes: 5 additions & 4 deletions requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ cffi==1.16.0
# via
# -r requirements/test.txt
# pynacl
charset-normalizer==3.3.0
charset-normalizer==3.3.1
# via requests
click==8.1.7
# via
Expand All @@ -30,6 +30,7 @@ code-annotations==1.5.0
coverage[toml]==7.3.2
# via
# -r requirements/test.txt
# coverage
# pytest-cov
django==3.2.22
# via
Expand Down Expand Up @@ -81,7 +82,7 @@ markupsafe==2.1.3
# via
# -r requirements/test.txt
# jinja2
newrelic==9.1.0
newrelic==9.1.1
# via
# -r requirements/test.txt
# edx-django-utils
Expand All @@ -100,7 +101,7 @@ pluggy==1.3.0
# via
# -r requirements/test.txt
# pytest
psutil==5.9.5
psutil==5.9.6
# via
# -r requirements/test.txt
# edx-django-utils
Expand Down Expand Up @@ -189,7 +190,7 @@ typing-extensions==4.8.0
# via
# -r requirements/test.txt
# asgiref
urllib3==2.0.6
urllib3==2.0.7
# via requests
zipp==3.17.0
# via importlib-metadata
2 changes: 1 addition & 1 deletion requirements/pip.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ wheel==0.41.2
# via -r requirements/pip.in

# The following packages are considered to be unsafe in a requirements file:
pip==23.2.1
pip==23.3.1
# via -r requirements/pip.in
setuptools==68.2.2
# via -r requirements/pip.in
21 changes: 9 additions & 12 deletions requirements/quality.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ asgiref==3.7.2
# via
# -r requirements/test.txt
# django
astroid==2.15.8
astroid==3.0.1
# via
# pylint
# pylint-celery
Expand All @@ -19,7 +19,7 @@ cffi==1.16.0
# -r requirements/test.txt
# cryptography
# pynacl
charset-normalizer==3.3.0
charset-normalizer==3.3.1
# via requests
click==8.1.7
# via
Expand All @@ -37,6 +37,7 @@ code-annotations==1.5.0
coverage[toml]==7.3.2
# via
# -r requirements/test.txt
# coverage
# pytest-cov
cryptography==41.0.4
# via secretstorage
Expand Down Expand Up @@ -95,8 +96,6 @@ jinja2==3.1.2
# code-annotations
keyring==24.2.0
# via twine
lazy-object-proxy==1.9.0
# via astroid
markdown-it-py==3.0.0
# via rich
markupsafe==2.1.3
Expand All @@ -109,7 +108,7 @@ mdurl==0.1.2
# via markdown-it-py
more-itertools==10.1.0
# via jaraco-classes
newrelic==9.1.0
newrelic==9.1.1
# via
# -r requirements/test.txt
# edx-django-utils
Expand All @@ -131,11 +130,11 @@ pluggy==1.3.0
# via
# -r requirements/test.txt
# pytest
psutil==5.9.5
psutil==5.9.6
# via
# -r requirements/test.txt
# edx-django-utils
pycodestyle==2.11.0
pycodestyle==2.11.1
# via -r requirements/quality.in
pycparser==2.21
# via
Expand All @@ -147,15 +146,15 @@ pygments==2.16.1
# via
# readme-renderer
# rich
pylint==2.17.7
pylint==3.0.2
# via
# edx-lint
# pylint-celery
# pylint-django
# pylint-plugin-utils
pylint-celery==0.3
# via edx-lint
pylint-django==2.5.3
pylint-django==2.5.5
# via edx-lint
pylint-plugin-utils==0.8.2
# via
Expand Down Expand Up @@ -234,12 +233,10 @@ typing-extensions==4.8.0
# astroid
# pylint
# rich
urllib3==2.0.6
urllib3==2.0.7
# via
# requests
# twine
wrapt==1.15.0
# via astroid
zipp==3.17.0
# via
# importlib-metadata
Expand Down
Loading

0 comments on commit fe6e73e

Please sign in to comment.