Skip to content

Commit d87ec82

Browse files
committed
Closes #6590: Introduce a nightly housekeeping command to clear expired sessions and change records
1 parent a1ba3b5 commit d87ec82

File tree

8 files changed

+93
-12
lines changed

8 files changed

+93
-12
lines changed

contrib/netbox-housekeeping.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
# This shell script invokes NetBox's housekeeping management command, which
3+
# intended to be run nightly. This script can be copied into your system's
4+
# daily cron directory (e.g. /etc/cron.daily), or referenced directly from
5+
# within the cron configuration file.
6+
#
7+
# If NetBox has been installed into a nonstandard location, update the paths
8+
# below.
9+
/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py housekeeping

docs/administration/housekeeping.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Housekeeping
2+
3+
NetBox includes a `housekeeping` management command that should be run nightly. This command handles:
4+
5+
* Clearing expired authentication sessions from the database
6+
* Deleting changelog records older than the configured [retention time](../configuration/optional-settings.md#changelog_retention)
7+
8+
This command can be invoked directly, or by using the shell script provided at `/opt/netbox/contrib/netbox-housekeeping.sh`. This script can be copied into your cron scheduler's daily jobs directory (e.g. `/etc/cron.daily`) or referenced directly within the cron configuration file.
9+
10+
The `housekeeping` command can also be run manually at any time: Running the command outside of scheduled execution times will not interfere with its operation.

docs/installation/3-netbox.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,18 @@ Password (again):
247247
Superuser created successfully.
248248
```
249249

250+
## Schedule the Housekeeping Task
251+
252+
NetBox includes a `housekeeping` management command that handles some recurring cleanup tasks, such as clearing out old sessions and expired change records. Although this command may be run manually, it is recommended to configure a scheduled job using the system's `cron` daemon or a similar utility.
253+
254+
A shell script which invokes this command is included at `contrib/netbox-housekeeping.sh`. It can be copied to your system's daily cron task directory, or included within the crontab directly. (If installing NetBox into a nonstandard path, be sure to update the system paths within this script first.)
255+
256+
```shell
257+
cp /opt/netbox/contrib/netbox-housekeeping.sh /etc/cron.daily/
258+
```
259+
260+
See the [housekeeping documentation](../administration/housekeeping.md) for further details.
261+
250262
## Test the Application
251263

252264
At this point, we should be able to run NetBox's development server for testing. We can check by starting a development instance:

docs/installation/upgrading.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,12 @@ Finally, restart the gunicorn and RQ services:
102102
sudo systemctl restart netbox netbox-rq
103103
```
104104

105-
!!! note
106-
If upgrading from an installation that uses supervisord, please see the instructions for [migrating to systemd](migrating-to-systemd.md). The use of supervisord is no longer supported.
105+
## Verify Housekeeping Scheduling
106+
107+
If upgrading from a release prior to NetBox v3.0, check that a cron task (or similar scheduled process) has been configured to run NetBox's nightly housekeeping command. A shell script which invokes this command is included at `contrib/netbox-housekeeping.sh`. It can be copied to your system's daily cron task directory, or included within the crontab directly. (If NetBox has been installed in a nonstandard path, be sure to update the system paths within this script first.)
108+
109+
```shell
110+
cp /opt/netbox/contrib/netbox-housekeeping.sh /etc/cron.daily/
111+
```
112+
113+
See the [housekeeping documentation](../administration/housekeeping.md) for further details.

docs/release-notes/version-3.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ CustomValidator can also be subclassed to enforce more complex logic by overridi
3939
* [#4609](https://github.com/netbox-community/netbox/issues/4609) - Allow marking prefixes as fully utilized
4040
* [#5806](https://github.com/netbox-community/netbox/issues/5806) - Add kilometer and mile as choices for cable length unit
4141
* [#6154](https://github.com/netbox-community/netbox/issues/6154) - Allow decimal values for cable lengths
42+
* [#6590](https://github.com/netbox-community/netbox/issues/6590) - Introduce a nightly housekeeping command to clear expired sessions and change records
4243

4344
### Other Changes
4445

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ nav:
7979
- Developing Plugins: 'plugins/development.md'
8080
- Administration:
8181
- Permissions: 'administration/permissions.md'
82+
- Housekeeping: 'administration/housekeeping.md'
8283
- Replicating NetBox: 'administration/replicating-netbox.md'
8384
- NetBox Shell: 'administration/netbox-shell.md'
8485
- REST API:
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from datetime import timedelta
2+
from importlib import import_module
3+
4+
from django.conf import settings
5+
from django.core.management.base import BaseCommand
6+
from django.db import DEFAULT_DB_ALIAS
7+
from django.utils import timezone
8+
9+
from extras.models import ObjectChange
10+
11+
12+
class Command(BaseCommand):
13+
help = "Perform nightly housekeeping tasks. (This command can be run at any time.)"
14+
15+
def handle(self, *args, **options):
16+
17+
# Clear expired authentication sessions (essentially replicating the `clearsessions` command)
18+
self.stdout.write("[*] Clearing expired authentication sessions")
19+
if options['verbosity'] >= 2:
20+
self.stdout.write(f"\tConfigured session engine: {settings.SESSION_ENGINE}")
21+
engine = import_module(settings.SESSION_ENGINE)
22+
try:
23+
engine.SessionStore.clear_expired()
24+
self.stdout.write("\tSessions cleared.", self.style.SUCCESS)
25+
except NotImplementedError:
26+
self.stdout.write(
27+
f"\tThe configured session engine ({settings.SESSION_ENGINE}) does not support "
28+
f"clearing sessions; skipping."
29+
)
30+
31+
# Delete expired ObjectRecords
32+
self.stdout.write("[*] Checking for expired changelog records")
33+
if settings.CHANGELOG_RETENTION:
34+
cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
35+
if options['verbosity'] >= 2:
36+
self.stdout.write(f"Retention period: {settings.CHANGELOG_RETENTION} days")
37+
self.stdout.write(f"\tCut-off time: {cutoff}")
38+
expired_records = ObjectChange.objects.filter(time__lt=cutoff).count()
39+
if expired_records:
40+
self.stdout.write(f"\tDeleting {expired_records} expired records... ", self.style.WARNING, ending="")
41+
self.stdout.flush()
42+
ObjectChange.objects.filter(time__lt=cutoff)._raw_delete(using=DEFAULT_DB_ALIAS)
43+
self.stdout.write("Done.", self.style.WARNING)
44+
else:
45+
self.stdout.write("\tNo expired records found.")
46+
else:
47+
self.stdout.write(
48+
f"\tSkipping: No retention period specified (CHANGELOG_RETENTION = {settings.CHANGELOG_RETENTION})"
49+
)
50+
51+
self.stdout.write("Finished.", self.style.SUCCESS)

netbox/extras/signals.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
import random
2-
from datetime import timedelta
3-
41
from cacheops.signals import cache_invalidated, cache_read
52
from django.conf import settings
63
from django.contrib.contenttypes.models import ContentType
7-
from django.db import DEFAULT_DB_ALIAS
84
from django.db.models.signals import m2m_changed, post_save, pre_delete
95
from django.dispatch import receiver
10-
from django.utils import timezone
116
from django_prometheus.models import model_deletes, model_inserts, model_updates
127
from prometheus_client import Counter
138

@@ -79,11 +74,6 @@ def is_same_object(instance, webhook_data):
7974
elif action == ObjectChangeActionChoices.ACTION_UPDATE:
8075
model_updates.labels(instance._meta.model_name).inc()
8176

82-
# Housekeeping: 0.1% chance of clearing out expired ObjectChanges
83-
if settings.CHANGELOG_RETENTION and random.randint(1, 1000) == 1:
84-
cutoff = timezone.now() - timedelta(days=settings.CHANGELOG_RETENTION)
85-
ObjectChange.objects.filter(time__lt=cutoff)._raw_delete(using=DEFAULT_DB_ALIAS)
86-
8777

8878
def _handle_deleted_object(request, webhook_queue, sender, instance, **kwargs):
8979
"""

0 commit comments

Comments
 (0)