Remove stats from the model, move it to hosts
The stats table was redundant - it linked the stats for a host to a playbook. The hosts are already linked to the playbooks. Change-Id: I47dd903b73f9b6e9007c8fdfbc0c99dfa6f3f703
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 2.1.7 on 2019-02-22 19:43
|
||||
# Generated by Django 2.1.7 on 2019-03-19 00:42
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
@@ -47,6 +47,11 @@ class Migration(migrations.Migration):
|
||||
('name', models.CharField(max_length=255)),
|
||||
('facts', models.BinaryField(max_length=4294967295)),
|
||||
('alias', models.CharField(max_length=255, null=True)),
|
||||
('changed', models.IntegerField(default=0)),
|
||||
('failed', models.IntegerField(default=0)),
|
||||
('ok', models.IntegerField(default=0)),
|
||||
('skipped', models.IntegerField(default=0)),
|
||||
('unreachable', models.IntegerField(default=0)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'hosts',
|
||||
@@ -133,24 +138,6 @@ class Migration(migrations.Migration):
|
||||
'db_table': 'results',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Stats',
|
||||
fields=[
|
||||
('id', models.BigAutoField(editable=False, primary_key=True, serialize=False)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('changed', models.IntegerField(default=0)),
|
||||
('failed', models.IntegerField(default=0)),
|
||||
('ok', models.IntegerField(default=0)),
|
||||
('skipped', models.IntegerField(default=0)),
|
||||
('unreachable', models.IntegerField(default=0)),
|
||||
('host', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stats', to='api.Host')),
|
||||
('playbook', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stats', to='api.Playbook')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'stats',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Task',
|
||||
fields=[
|
||||
@@ -198,10 +185,6 @@ class Migration(migrations.Migration):
|
||||
name='playbook',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='api.Playbook'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='stats',
|
||||
unique_together={('host', 'playbook')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='record',
|
||||
unique_together={('key', 'playbook')},
|
||||
|
||||
@@ -220,34 +220,17 @@ class Host(Base):
|
||||
# The logic for supplying aliases does not live here, it's provided by the
|
||||
# clients and consumers.
|
||||
alias = models.CharField(max_length=255, null=True)
|
||||
playbook = models.ForeignKey(Playbook, on_delete=models.CASCADE, related_name="hosts")
|
||||
|
||||
def __str__(self):
|
||||
return "<Host %s:%s>" % (self.id, self.name)
|
||||
|
||||
|
||||
class Stats(Base):
|
||||
"""
|
||||
Stats for a host for a playbook.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
db_table = "stats"
|
||||
unique_together = ("host", "playbook")
|
||||
|
||||
playbook = models.ForeignKey(Playbook, on_delete=models.CASCADE, related_name="stats")
|
||||
host = models.ForeignKey(Host, on_delete=models.CASCADE, related_name="stats")
|
||||
changed = models.IntegerField(default=0)
|
||||
failed = models.IntegerField(default=0)
|
||||
ok = models.IntegerField(default=0)
|
||||
skipped = models.IntegerField(default=0)
|
||||
unreachable = models.IntegerField(default=0)
|
||||
|
||||
playbook = models.ForeignKey(Playbook, on_delete=models.CASCADE, related_name="hosts")
|
||||
|
||||
def __str__(self):
|
||||
# Verbose because it's otherwise kind of useless
|
||||
return "<Stats for {host} ({id}) in playbook {playbook}>".format(
|
||||
host=self.host.name, id=self.host.id, playbook=self.playbook.id
|
||||
)
|
||||
return "<Host %s:%s>" % (self.id, self.name)
|
||||
|
||||
|
||||
class Result(Duration):
|
||||
|
||||
@@ -148,12 +148,6 @@ class SimplePlaySerializer(serializers.ModelSerializer):
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class StatsSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = models.Stats
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class PlaybookSerializer(DurationSerializer):
|
||||
class Meta:
|
||||
model = models.Playbook
|
||||
|
||||
@@ -121,16 +121,3 @@ class RecordFactory(factory.DjangoModelFactory):
|
||||
value = utils.compressed_obj(RECORD_LIST)
|
||||
type = "list"
|
||||
playbook = factory.SubFactory(PlaybookFactory)
|
||||
|
||||
|
||||
class StatsFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = models.Stats
|
||||
|
||||
changed = 1
|
||||
failed = 0
|
||||
ok = 2
|
||||
skipped = 1
|
||||
unreachable = 0
|
||||
playbook = factory.SubFactory(PlaybookFactory)
|
||||
host = factory.SubFactory(HostFactory)
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of ARA Records Ansible.
|
||||
#
|
||||
# ARA is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ARA is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with ARA. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from ara.api import models, serializers
|
||||
from ara.api.tests import factories
|
||||
|
||||
|
||||
class StatsTestCase(APITestCase):
|
||||
def test_stats_factory(self):
|
||||
stats = factories.StatsFactory(changed=2, failed=1, ok=3, skipped=2, unreachable=1)
|
||||
self.assertEqual(stats.changed, 2)
|
||||
self.assertEqual(stats.failed, 1)
|
||||
self.assertEqual(stats.ok, 3)
|
||||
self.assertEqual(stats.skipped, 2)
|
||||
self.assertEqual(stats.unreachable, 1)
|
||||
|
||||
def test_stats_serializer(self):
|
||||
playbook = factories.PlaybookFactory()
|
||||
host = factories.HostFactory()
|
||||
serializer = serializers.StatsSerializer(data=dict(playbook=playbook.id, host=host.id, ok=9001))
|
||||
serializer.is_valid()
|
||||
stats = serializer.save()
|
||||
stats.refresh_from_db()
|
||||
self.assertEqual(stats.playbook.id, playbook.id)
|
||||
self.assertEqual(stats.host.id, host.id)
|
||||
self.assertEqual(stats.ok, 9001)
|
||||
|
||||
def test_create_stats(self):
|
||||
playbook = factories.PlaybookFactory()
|
||||
host = factories.HostFactory()
|
||||
self.assertEqual(0, models.Stats.objects.count())
|
||||
request = self.client.post("/api/v1/stats", dict(playbook=playbook.id, host=host.id, ok=9001))
|
||||
self.assertEqual(201, request.status_code)
|
||||
self.assertEqual(1, models.Stats.objects.count())
|
||||
|
||||
def test_get_no_stats(self):
|
||||
request = self.client.get("/api/v1/stats")
|
||||
self.assertEqual(0, len(request.data["results"]))
|
||||
|
||||
def test_get_stats(self):
|
||||
stats = factories.StatsFactory()
|
||||
request = self.client.get("/api/v1/stats")
|
||||
self.assertEqual(1, len(request.data["results"]))
|
||||
self.assertEqual(stats.ok, request.data["results"][0]["ok"])
|
||||
|
||||
def test_get_stats_by_playbook(self):
|
||||
playbook = factories.PlaybookFactory()
|
||||
host_one = factories.HostFactory(name="one")
|
||||
host_two = factories.HostFactory(name="two")
|
||||
stats = factories.StatsFactory(host=host_one, playbook=playbook, ok=9001)
|
||||
factories.StatsFactory(host=host_two, playbook=playbook)
|
||||
request = self.client.get("/api/v1/stats?playbook=%s" % playbook.id)
|
||||
self.assertEqual(2, len(request.data["results"]))
|
||||
self.assertEqual(host_one.id, request.data["results"][0]["id"])
|
||||
self.assertEqual(stats.ok, request.data["results"][0]["ok"])
|
||||
self.assertEqual(host_two.id, request.data["results"][1]["id"])
|
||||
|
||||
def test_get_stats_by_host(self):
|
||||
playbook = factories.PlaybookFactory()
|
||||
host_one = factories.HostFactory(name="one")
|
||||
host_two = factories.HostFactory(name="two")
|
||||
stats = factories.StatsFactory(host=host_one, playbook=playbook, ok=9001)
|
||||
factories.StatsFactory(host=host_two, playbook=playbook)
|
||||
request = self.client.get("/api/v1/stats?host=%s" % host_one.id)
|
||||
self.assertEqual(1, len(request.data["results"]))
|
||||
self.assertEqual(stats.ok, request.data["results"][0]["ok"])
|
||||
self.assertEqual(host_one.id, request.data["results"][0]["id"])
|
||||
|
||||
def test_get_stats_id(self):
|
||||
stats = factories.StatsFactory()
|
||||
request = self.client.get("/api/v1/stats/%s" % stats.id)
|
||||
self.assertEqual(stats.ok, request.data["ok"])
|
||||
|
||||
def test_partial_update_stats(self):
|
||||
stats = factories.StatsFactory()
|
||||
self.assertNotEqual(9001, stats.ok)
|
||||
request = self.client.patch("/api/v1/stats/%s" % stats.id, dict(ok=9001))
|
||||
self.assertEqual(200, request.status_code)
|
||||
stats_updated = models.Stats.objects.get(id=stats.id)
|
||||
self.assertEqual(9001, stats_updated.ok)
|
||||
|
||||
def test_delete_stats(self):
|
||||
stats = factories.StatsFactory()
|
||||
self.assertEqual(1, models.Stats.objects.all().count())
|
||||
request = self.client.delete("/api/v1/stats/%s" % stats.id)
|
||||
self.assertEqual(204, request.status_code)
|
||||
self.assertEqual(0, models.Stats.objects.all().count())
|
||||
@@ -28,7 +28,6 @@ router.register("hosts", views.HostViewSet, base_name="host")
|
||||
router.register("results", views.ResultViewSet, base_name="result")
|
||||
router.register("files", views.FileViewSet, base_name="file")
|
||||
router.register("records", views.RecordViewSet, base_name="record")
|
||||
router.register("stats", views.StatsViewSet, base_name="stats")
|
||||
router.register("info", views.InfoView, base_name="info")
|
||||
|
||||
urlpatterns = router.urls
|
||||
|
||||
@@ -83,9 +83,3 @@ class RecordViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Record.objects.all()
|
||||
serializer_class = serializers.RecordSerializer
|
||||
filter_fields = ("playbook", "key")
|
||||
|
||||
|
||||
class StatsViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Stats.objects.all()
|
||||
serializer_class = serializers.StatsSerializer
|
||||
filter_fields = ("playbook", "host")
|
||||
|
||||
Reference in New Issue
Block a user