forked from ansible/awx
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HostMetrics: Hard auto-cleanup (ansible#14255)
Fix host metric settings Cleanup_host_metric command with default params Fix order of host metric cleanups
- Loading branch information
1 parent
e76f632
commit 8e6b1d1
Showing
7 changed files
with
170 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,22 @@ | ||
from awx.main.models import HostMetric | ||
from django.core.management.base import BaseCommand | ||
from django.conf import settings | ||
from awx.main.tasks.host_metrics import HostMetricTask | ||
|
||
|
||
class Command(BaseCommand): | ||
""" | ||
Run soft-deleting of HostMetrics | ||
This command provides cleanup task for HostMetric model. | ||
There are two modes, which run in following order: | ||
- soft cleanup | ||
- - Perform soft-deletion of all host metrics last automated 12 months ago or before. | ||
This is the same as issuing a DELETE request to /api/v2/host_metrics/N/ for all host metrics that match the criteria. | ||
- - updates columns delete, deleted_counter and last_deleted | ||
- hard cleanup | ||
- - Permanently erase from the database all host metrics last automated 36 months ago or before. | ||
This operation happens after the soft deletion has finished. | ||
""" | ||
|
||
help = 'Run soft-deleting of HostMetrics' | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument('--months-ago', type=int, dest='months-ago', action='store', help='Threshold in months for soft-deleting') | ||
help = 'Run soft and hard-deletion of HostMetrics' | ||
|
||
def handle(self, *args, **options): | ||
months_ago = options.get('months-ago') or None | ||
|
||
if not months_ago: | ||
months_ago = getattr(settings, 'CLEANUP_HOST_METRICS_SOFT_THRESHOLD', 12) | ||
|
||
HostMetric.cleanup_task(months_ago) | ||
HostMetricTask().cleanup(soft_threshold=settings.CLEANUP_HOST_METRICS_SOFT_THRESHOLD, hard_threshold=settings.CLEANUP_HOST_METRICS_HARD_THRESHOLD) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from django.utils.timezone import now | ||
from rest_framework.fields import DateTimeField | ||
|
||
|
||
def is_run_threshold_reached(setting, threshold_seconds): | ||
last_time = DateTimeField().to_internal_value(setting) if setting else None | ||
if not last_time: | ||
return True | ||
else: | ||
return (now() - last_time).total_seconds() > threshold_seconds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
awx/main/tests/functional/commands/test_cleanup_host_metrics.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import pytest | ||
|
||
from awx.main.tasks.host_metrics import HostMetricTask | ||
from awx.main.models.inventory import HostMetric | ||
from awx.main.tests.factories.fixtures import mk_host_metric | ||
from dateutil.relativedelta import relativedelta | ||
from django.conf import settings | ||
from django.utils import timezone | ||
|
||
|
||
@pytest.mark.django_db | ||
def test_no_host_metrics(): | ||
"""No-crash test""" | ||
assert HostMetric.objects.count() == 0 | ||
HostMetricTask().cleanup(soft_threshold=0, hard_threshold=0) | ||
HostMetricTask().cleanup(soft_threshold=24, hard_threshold=42) | ||
assert HostMetric.objects.count() == 0 | ||
|
||
|
||
@pytest.mark.django_db | ||
def test_delete_exception(): | ||
"""Crash test""" | ||
with pytest.raises(ValueError): | ||
HostMetricTask().soft_cleanup("") | ||
with pytest.raises(TypeError): | ||
HostMetricTask().hard_cleanup(set()) | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize('threshold', [settings.CLEANUP_HOST_METRICS_SOFT_THRESHOLD, 20]) | ||
def test_soft_delete(threshold): | ||
"""Metrics with last_automation < threshold are updated to deleted=True""" | ||
mk_host_metric('host_1', first_automation=ago(months=1), last_automation=ago(months=1), deleted=False) | ||
mk_host_metric('host_2', first_automation=ago(months=1), last_automation=ago(months=1), deleted=True) | ||
mk_host_metric('host_3', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=-1), deleted=False) | ||
mk_host_metric('host_4', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=-1), deleted=True) | ||
mk_host_metric('host_5', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=1), deleted=False) | ||
mk_host_metric('host_6', first_automation=ago(months=1), last_automation=ago(months=threshold, hours=1), deleted=True) | ||
mk_host_metric('host_7', first_automation=ago(months=1), last_automation=ago(months=42), deleted=False) | ||
mk_host_metric('host_8', first_automation=ago(months=1), last_automation=ago(months=42), deleted=True) | ||
|
||
assert HostMetric.objects.count() == 8 | ||
assert HostMetric.active_objects.count() == 4 | ||
|
||
for i in range(2): | ||
HostMetricTask().cleanup(soft_threshold=threshold) | ||
assert HostMetric.objects.count() == 8 | ||
|
||
hostnames = set(HostMetric.objects.filter(deleted=False).order_by('hostname').values_list('hostname', flat=True)) | ||
assert hostnames == {'host_1', 'host_3'} | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize('threshold', [settings.CLEANUP_HOST_METRICS_HARD_THRESHOLD, 20]) | ||
def test_hard_delete(threshold): | ||
"""Metrics with last_deleted < threshold and deleted=True are deleted from the db""" | ||
mk_host_metric('host_1', first_automation=ago(months=1), last_deleted=ago(months=1), deleted=False) | ||
mk_host_metric('host_2', first_automation=ago(months=1), last_deleted=ago(months=1), deleted=True) | ||
mk_host_metric('host_3', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=-1), deleted=False) | ||
mk_host_metric('host_4', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=-1), deleted=True) | ||
mk_host_metric('host_5', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=1), deleted=False) | ||
mk_host_metric('host_6', first_automation=ago(months=1), last_deleted=ago(months=threshold, hours=1), deleted=True) | ||
mk_host_metric('host_7', first_automation=ago(months=1), last_deleted=ago(months=42), deleted=False) | ||
mk_host_metric('host_8', first_automation=ago(months=1), last_deleted=ago(months=42), deleted=True) | ||
|
||
assert HostMetric.objects.count() == 8 | ||
assert HostMetric.active_objects.count() == 4 | ||
|
||
for i in range(2): | ||
HostMetricTask().cleanup(hard_threshold=threshold) | ||
assert HostMetric.objects.count() == 6 | ||
|
||
hostnames = set(HostMetric.objects.order_by('hostname').values_list('hostname', flat=True)) | ||
assert hostnames == {'host_1', 'host_2', 'host_3', 'host_4', 'host_5', 'host_7'} | ||
|
||
|
||
def ago(months=0, hours=0): | ||
return timezone.now() - relativedelta(months=months, hours=hours) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters