diff options
Diffstat (limited to 'releng')
-rw-r--r-- | releng/__init__.py | 0 | ||||
-rw-r--r-- | releng/admin.py | 18 | ||||
-rw-r--r-- | releng/fixtures/architecture.json | 30 | ||||
-rw-r--r-- | releng/fixtures/bootloaders.json | 23 | ||||
-rw-r--r-- | releng/fixtures/boottype.json | 23 | ||||
-rw-r--r-- | releng/fixtures/clockchoices.json | 23 | ||||
-rw-r--r-- | releng/fixtures/filesystems.json | 23 | ||||
-rw-r--r-- | releng/fixtures/hardware.json | 44 | ||||
-rw-r--r-- | releng/fixtures/installtype.json | 30 | ||||
-rw-r--r-- | releng/fixtures/isotypes.json | 16 | ||||
-rw-r--r-- | releng/fixtures/modules.json | 86 | ||||
-rw-r--r-- | releng/fixtures/source.json | 23 | ||||
-rw-r--r-- | releng/management/__init__.py | 0 | ||||
-rw-r--r-- | releng/management/commands/__init__.py | 0 | ||||
-rw-r--r-- | releng/management/commands/syncisos.py | 48 | ||||
-rw-r--r-- | releng/migrations/0001_initial.py | 258 | ||||
-rw-r--r-- | releng/migrations/__init__.py | 0 | ||||
-rw-r--r-- | releng/models.py | 121 | ||||
-rw-r--r-- | releng/urls.py | 11 | ||||
-rw-r--r-- | releng/views.py | 132 |
20 files changed, 909 insertions, 0 deletions
diff --git a/releng/__init__.py b/releng/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/__init__.py diff --git a/releng/admin.py b/releng/admin.py new file mode 100644 index 00000000..10acaa98 --- /dev/null +++ b/releng/admin.py @@ -0,0 +1,18 @@ +from django.contrib import admin + +from .models import (Architecture, BootType, Bootloader, ClockChoice, + Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source) + +admin.site.register(Iso) +admin.site.register(Architecture) +admin.site.register(IsoType) +admin.site.register(BootType) +admin.site.register(HardwareType) +admin.site.register(InstallType) +admin.site.register(Source) +admin.site.register(ClockChoice) +admin.site.register(Filesystem) +admin.site.register(Module) +admin.site.register(Bootloader) + +# vim: set ts=4 sw=4 et: diff --git a/releng/fixtures/architecture.json b/releng/fixtures/architecture.json new file mode 100644 index 00000000..0bf9b8bf --- /dev/null +++ b/releng/fixtures/architecture.json @@ -0,0 +1,30 @@ +[ + { + "pk": 1, + "model": "releng.architecture", + "fields": { + "name": "dual, option i686" + } + }, + { + "pk": 2, + "model": "releng.architecture", + "fields": { + "name": "dual, option x86_64" + } + }, + { + "pk": 3, + "model": "releng.architecture", + "fields": { + "name": "i686" + } + }, + { + "pk": 4, + "model": "releng.architecture", + "fields": { + "name": "x86_64" + } + } +] diff --git a/releng/fixtures/bootloaders.json b/releng/fixtures/bootloaders.json new file mode 100644 index 00000000..bee02f2b --- /dev/null +++ b/releng/fixtures/bootloaders.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.bootloader", + "fields": { + "name": "grub" + } + }, + { + "pk": 2, + "model": "releng.bootloader", + "fields": { + "name": "syslinux" + } + }, + { + "pk": 3, + "model": "releng.bootloader", + "fields": { + "name": "other/manual" + } + } +] diff --git a/releng/fixtures/boottype.json b/releng/fixtures/boottype.json new file mode 100644 index 00000000..ed4636eb --- /dev/null +++ b/releng/fixtures/boottype.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.boottype", + "fields": { + "name": "optical" + } + }, + { + "pk": 2, + "model": "releng.boottype", + "fields": { + "name": "usb" + } + }, + { + "pk": 3, + "model": "releng.boottype", + "fields": { + "name": "pxe" + } + } +] diff --git a/releng/fixtures/clockchoices.json b/releng/fixtures/clockchoices.json new file mode 100644 index 00000000..f328801a --- /dev/null +++ b/releng/fixtures/clockchoices.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.clockchoice", + "fields": { + "name": "unchanged" + } + }, + { + "pk": 2, + "model": "releng.clockchoice", + "fields": { + "name": "configured manually" + } + }, + { + "pk": 3, + "model": "releng.clockchoice", + "fields": { + "name": "NTP" + } + } +] diff --git a/releng/fixtures/filesystems.json b/releng/fixtures/filesystems.json new file mode 100644 index 00000000..208f5c73 --- /dev/null +++ b/releng/fixtures/filesystems.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.filesystem", + "fields": { + "name": "autoprepare" + } + }, + { + "pk": 2, + "model": "releng.filesystem", + "fields": { + "name": "manual" + } + }, + { + "pk": 3, + "model": "releng.filesystem", + "fields": { + "name": "from config file" + } + } +] diff --git a/releng/fixtures/hardware.json b/releng/fixtures/hardware.json new file mode 100644 index 00000000..a2bb9ec0 --- /dev/null +++ b/releng/fixtures/hardware.json @@ -0,0 +1,44 @@ +[ + { + "pk": 1, + "model": "releng.hardwaretype", + "fields": { + "name": "virtualbox" + } + }, + { + "pk": 2, + "model": "releng.hardwaretype", + "fields": { + "name": "qemu" + } + }, + { + "pk": 3, + "model": "releng.hardwaretype", + "fields": { + "name": "intel i686" + } + }, + { + "pk": 4, + "model": "releng.hardwaretype", + "fields": { + "name": "intel x86_64" + } + }, + { + "pk": 5, + "model": "releng.hardwaretype", + "fields": { + "name": "amd i686" + } + }, + { + "pk": 6, + "model": "releng.hardwaretype", + "fields": { + "name": "amd x86_64" + } + } +] diff --git a/releng/fixtures/installtype.json b/releng/fixtures/installtype.json new file mode 100644 index 00000000..7fa21fc1 --- /dev/null +++ b/releng/fixtures/installtype.json @@ -0,0 +1,30 @@ +[ + { + "pk": 1, + "model": "releng.installtype", + "fields": { + "name": "interactive install" + } + }, + { + "pk": 2, + "model": "releng.installtype", + "fields": { + "name": "automatic install generic example" + } + }, + { + "pk": 3, + "model": "releng.installtype", + "fields": { + "name": "automatic install fancy example" + } + }, + { + "pk": 4, + "model": "releng.installtype", + "fields": { + "name": "automatic install custom config (specify in comments)" + } + } +] diff --git a/releng/fixtures/isotypes.json b/releng/fixtures/isotypes.json new file mode 100644 index 00000000..a529b181 --- /dev/null +++ b/releng/fixtures/isotypes.json @@ -0,0 +1,16 @@ +[ + { + "pk": 1, + "model": "releng.isotype", + "fields": { + "name": "core" + } + }, + { + "pk": 2, + "model": "releng.isotype", + "fields": { + "name": "net" + } + } +] diff --git a/releng/fixtures/modules.json b/releng/fixtures/modules.json new file mode 100644 index 00000000..9cdf1a8d --- /dev/null +++ b/releng/fixtures/modules.json @@ -0,0 +1,86 @@ +[ + { + "pk": 1, + "model": "releng.module", + "fields": { + "name": "lvm2" + } + }, + { + "pk": 2, + "model": "releng.module", + "fields": { + "name": "dm_crypt" + } + }, + { + "pk": 3, + "model": "releng.module", + "fields": { + "name": "softraid" + } + }, + { + "pk": 4, + "model": "releng.module", + "fields": { + "name": "nilfs2" + } + }, + { + "pk": 5, + "model": "releng.module", + "fields": { + "name": "btrfs" + } + }, + { + "pk": 6, + "model": "releng.module", + "fields": { + "name": "ext2" + } + }, + { + "pk": 7, + "model": "releng.module", + "fields": { + "name": "ext3" + } + }, + { + "pk": 8, + "model": "releng.module", + "fields": { + "name": "ext4" + } + }, + { + "pk": 9, + "model": "releng.module", + "fields": { + "name": "swap" + } + }, + { + "pk": 10, + "model": "releng.module", + "fields": { + "name": "xfs" + } + }, + { + "pk": 11, + "model": "releng.module", + "fields": { + "name": "jfs" + } + }, + { + "pk": 12, + "model": "releng.module", + "fields": { + "name": "reiserFS" + } + } +] diff --git a/releng/fixtures/source.json b/releng/fixtures/source.json new file mode 100644 index 00000000..2622f4c1 --- /dev/null +++ b/releng/fixtures/source.json @@ -0,0 +1,23 @@ +[ + { + "pk": 1, + "model": "releng.source", + "fields": { + "name": "net install manual networking config (Check that it works + rc.conf, resolv.conf, mirrorlist)" + } + }, + { + "pk": 2, + "model": "releng.source", + "fields": { + "name": "net install dhcp (Check that it works + rc.conf)" + } + }, + { + "pk": 3, + "model": "releng.source", + "fields": { + "name": "core" + } + } +] diff --git a/releng/management/__init__.py b/releng/management/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/management/__init__.py diff --git a/releng/management/commands/__init__.py b/releng/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/management/commands/__init__.py diff --git a/releng/management/commands/syncisos.py b/releng/management/commands/syncisos.py new file mode 100644 index 00000000..247b01cd --- /dev/null +++ b/releng/management/commands/syncisos.py @@ -0,0 +1,48 @@ +import re +import urllib +from HTMLParser import HTMLParser, HTMLParseError + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + +from releng.models import Iso + +class IsoListParser(HTMLParser): + def __init__(self): + HTMLParser.__init__(self) + + self.hyperlinks = [] + self.url_re = re.compile('(?!\.{2})/$') + + def handle_starttag(self, tag, attrs): + if tag == 'a': + for name, value in attrs: + if name == "href": + if value != '../' and self.url_re.search(value) != None: + self.hyperlinks.append(value[:len(value)-1]) + + def parse(self, url): + try: + remote_file = urllib.urlopen(url) + data = remote_file.read() + remote_file.close() + self.feed(data) + self.close() + return self.hyperlinks + except HTMLParseError: + raise CommandError('Couldn\'t parse "%s"' % url) + +class Command(BaseCommand): + help = 'Gets new isos from %s' % settings.ISO_LIST_URL + + def handle(self, *args, **options): + parser = IsoListParser() + isonames = Iso.objects.values_list('name', flat=True) + new_isos = parser.parse(settings.ISO_LIST_URL) + + for iso in new_isos: + if iso not in isonames: + new = Iso(name=iso) + new.save() + +# vim: set ts=4 sw=4 et: diff --git a/releng/migrations/0001_initial.py b/releng/migrations/0001_initial.py new file mode 100644 index 00000000..91fab8b7 --- /dev/null +++ b/releng/migrations/0001_initial.py @@ -0,0 +1,258 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Iso' + db.create_table('releng_iso', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('created', self.gf('django.db.models.fields.DateTimeField')()), + ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('releng', ['Iso']) + + # Adding model 'Architecture' + db.create_table('releng_architecture', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['Architecture']) + + # Adding model 'IsoType' + db.create_table('releng_isotype', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['IsoType']) + + # Adding model 'BootType' + db.create_table('releng_boottype', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['BootType']) + + # Adding model 'HardwareType' + db.create_table('releng_hardwaretype', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['HardwareType']) + + # Adding model 'InstallType' + db.create_table('releng_installtype', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['InstallType']) + + # Adding model 'Source' + db.create_table('releng_source', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['Source']) + + # Adding model 'ClockChoice' + db.create_table('releng_clockchoice', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['ClockChoice']) + + # Adding model 'Filesystem' + db.create_table('releng_filesystem', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['Filesystem']) + + # Adding model 'Module' + db.create_table('releng_module', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['Module']) + + # Adding model 'Bootloader' + db.create_table('releng_bootloader', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=200)), + )) + db.send_create_signal('releng', ['Bootloader']) + + # Adding model 'Test' + db.create_table('releng_test', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user_name', self.gf('django.db.models.fields.CharField')(max_length=500)), + ('user_email', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15)), + ('created', self.gf('django.db.models.fields.DateTimeField')()), + ('iso', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Iso'])), + ('architecture', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Architecture'])), + ('iso_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.IsoType'])), + ('boot_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.BootType'])), + ('hardware_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.HardwareType'])), + ('install_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.InstallType'])), + ('source', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Source'])), + ('clock_choice', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.ClockChoice'])), + ('filesystem', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Filesystem'])), + ('bootloader', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Bootloader'])), + ('rollback_filesystem', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='rollback_test_set', null=True, to=orm['releng.Filesystem'])), + ('success', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('comments', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + )) + db.send_create_signal('releng', ['Test']) + + # Adding M2M table for field modules on 'Test' + db.create_table('releng_test_modules', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('test', models.ForeignKey(orm['releng.test'], null=False)), + ('module', models.ForeignKey(orm['releng.module'], null=False)) + )) + db.create_unique('releng_test_modules', ['test_id', 'module_id']) + + # Adding M2M table for field rollback_modules on 'Test' + db.create_table('releng_test_rollback_modules', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('test', models.ForeignKey(orm['releng.test'], null=False)), + ('module', models.ForeignKey(orm['releng.module'], null=False)) + )) + db.create_unique('releng_test_rollback_modules', ['test_id', 'module_id']) + + + def backwards(self, orm): + + # Deleting model 'Iso' + db.delete_table('releng_iso') + + # Deleting model 'Architecture' + db.delete_table('releng_architecture') + + # Deleting model 'IsoType' + db.delete_table('releng_isotype') + + # Deleting model 'BootType' + db.delete_table('releng_boottype') + + # Deleting model 'HardwareType' + db.delete_table('releng_hardwaretype') + + # Deleting model 'InstallType' + db.delete_table('releng_installtype') + + # Deleting model 'Source' + db.delete_table('releng_source') + + # Deleting model 'ClockChoice' + db.delete_table('releng_clockchoice') + + # Deleting model 'Filesystem' + db.delete_table('releng_filesystem') + + # Deleting model 'Module' + db.delete_table('releng_module') + + # Deleting model 'Bootloader' + db.delete_table('releng_bootloader') + + # Deleting model 'Test' + db.delete_table('releng_test') + + # Removing M2M table for field modules on 'Test' + db.delete_table('releng_test_modules') + + # Removing M2M table for field rollback_modules on 'Test' + db.delete_table('releng_test_rollback_modules') + + + models = { + 'releng.architecture': { + 'Meta': {'object_name': 'Architecture'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.bootloader': { + 'Meta': {'object_name': 'Bootloader'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.boottype': { + 'Meta': {'object_name': 'BootType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.clockchoice': { + 'Meta': {'object_name': 'ClockChoice'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.filesystem': { + 'Meta': {'object_name': 'Filesystem'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.hardwaretype': { + 'Meta': {'object_name': 'HardwareType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.installtype': { + 'Meta': {'object_name': 'InstallType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.iso': { + 'Meta': {'object_name': 'Iso'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'releng.isotype': { + 'Meta': {'object_name': 'IsoType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.module': { + 'Meta': {'object_name': 'Module'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.source': { + 'Meta': {'object_name': 'Source'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'releng.test': { + 'Meta': {'object_name': 'Test'}, + 'architecture': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Architecture']"}), + 'boot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.BootType']"}), + 'bootloader': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Bootloader']"}), + 'clock_choice': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.ClockChoice']"}), + 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {}), + 'filesystem': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Filesystem']"}), + 'hardware_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.HardwareType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'install_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.InstallType']"}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'iso': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Iso']"}), + 'iso_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.IsoType']"}), + 'modules': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['releng.Module']", 'null': 'True', 'blank': 'True'}), + 'rollback_filesystem': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rollback_test_set'", 'null': 'True', 'to': "orm['releng.Filesystem']"}), + 'rollback_modules': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rollback_test_set'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['releng.Module']"}), + 'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Source']"}), + 'success': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + } + } + + complete_apps = ['releng'] diff --git a/releng/migrations/__init__.py b/releng/migrations/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/releng/migrations/__init__.py diff --git a/releng/models.py b/releng/models.py new file mode 100644 index 00000000..dc297d5b --- /dev/null +++ b/releng/models.py @@ -0,0 +1,121 @@ +from datetime import datetime + +from django.db import models +from django.db.models import Max + +class IsoOption(models.Model): + name = models.CharField(max_length=200) + + def __unicode__(self): + return self.name + + def get_test_result(self, success): + try: + return self.test_set.filter(success=success).select_related( + 'iso').latest('iso__id').iso + except Test.DoesNotExist: + return None + + def get_last_success(self): + return self.get_test_result(True) + + def get_last_failure(self): + return self.get_test_result(False) + + class Meta: + abstract = True + +class RollbackOption(IsoOption): + def get_rollback_test_result(self, success): + try: + return self.rollback_test_set.filter(success=success).select_related( + 'iso').latest('iso__id').iso + except Test.DoesNotExist: + return None + + def get_last_rollback_success(self): + return self.get_rollback_test_result(True) + + def get_last_rollback_failure(self): + return self.get_rollback_test_result(False) + + class Meta: + abstract = True + +class Iso(models.Model): + name = models.CharField(max_length=255) + created = models.DateTimeField(editable=False) + active = models.BooleanField(default=True) + + def __unicode__(self): + return self.name + +class Architecture(IsoOption): + pass + +class IsoType(IsoOption): + pass + +class BootType(IsoOption): + pass + +class HardwareType(IsoOption): + pass + +class InstallType(IsoOption): + pass + +class Source(IsoOption): + pass + +class ClockChoice(IsoOption): + pass + +class Filesystem(RollbackOption): + pass + +class Module(RollbackOption): + pass + +class Bootloader(IsoOption): + pass + +class Test(models.Model): + user_name = models.CharField(max_length=500) + user_email = models.EmailField() + ip_address = models.IPAddressField() + created = models.DateTimeField(editable=False) + + iso = models.ForeignKey(Iso) + architecture = models.ForeignKey(Architecture) + iso_type = models.ForeignKey(IsoType) + boot_type = models.ForeignKey(BootType) + hardware_type = models.ForeignKey(HardwareType) + install_type = models.ForeignKey(InstallType) + source = models.ForeignKey(Source) + clock_choice = models.ForeignKey(ClockChoice) + filesystem = models.ForeignKey(Filesystem) + modules = models.ManyToManyField(Module, null=True, blank=True) + bootloader = models.ForeignKey(Bootloader) + rollback_filesystem = models.ForeignKey(Filesystem, + related_name="rollback_test_set", null=True, blank=True) + rollback_modules = models.ManyToManyField(Module, + related_name="rollback_test_set", null=True, blank=True) + + success = models.BooleanField() + comments = models.TextField(null=True, blank=True) + +def set_created_field(sender, **kwargs): + # We use this same callback for both Isos and Tests + obj = kwargs['instance'] + if not obj.created: + obj.created = datetime.utcnow() + +from django.db.models.signals import pre_save + +pre_save.connect(set_created_field, sender=Iso, + dispatch_uid="releng.models") +pre_save.connect(set_created_field, sender=Test, + dispatch_uid="releng.models") + +# vim: set ts=4 sw=4 et: diff --git a/releng/urls.py b/releng/urls.py new file mode 100644 index 00000000..f76a9593 --- /dev/null +++ b/releng/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls.defaults import patterns + +urlpatterns = patterns('releng.views', + (r'^$', 'test_results_overview', {}, 'releng-test-overview'), + (r'^submit/$', 'submit_test_result', {}, 'releng-test-submit'), + (r'^thanks/$', 'submit_test_thanks', {}, 'releng-test-thanks'), + (r'^iso/(?P<iso_id>\d+)/$', 'test_results_iso', {}, 'releng-results-iso'), + (r'^(?P<option>.+)/(?P<value>\d+)/$','test_results_for', {}, 'releng-results-for'), +) + +# vim: set ts=4 sw=4 et: diff --git a/releng/views.py b/releng/views.py new file mode 100644 index 00000000..5cffb2f5 --- /dev/null +++ b/releng/views.py @@ -0,0 +1,132 @@ +from django import forms +from django.conf import settings +from django.http import Http404 +from django.shortcuts import get_object_or_404, redirect +from django.views.generic.simple import direct_to_template + +from .models import (Architecture, BootType, Bootloader, ClockChoice, + Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source, + Test) + +def standard_field(model, help_text=None): + return forms.ModelChoiceField(queryset=model.objects.all(), + widget=forms.RadioSelect(), empty_label=None, help_text=help_text) + +class TestForm(forms.ModelForm): + iso = forms.ModelChoiceField(queryset=Iso.objects.filter(active=True)) + architecture = standard_field(Architecture) + iso_type = standard_field(IsoType) + boot_type = standard_field(BootType) + hardware_type = standard_field(HardwareType) + install_type = standard_field(InstallType) + source = standard_field(Source) + clock_choice = standard_field(ClockChoice) + filesystem = standard_field(Filesystem, + help_text="Check the installed system, including fstab.") + modules = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), + help_text="", widget=forms.CheckboxSelectMultiple(), required=False) + bootloader = standard_field(Bootloader) + rollback_filesystem = forms.ModelChoiceField(queryset=Filesystem.objects.all(), + help_text="If you did a rollback followed by a new attempt to setup " \ + "your lockdevices/filesystems, select which option you took here.", + widget=forms.RadioSelect(), required=False) + rollback_modules = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), + help_text="If you did a rollback followed b a new attempt to setup " \ + "your lockdevices/filesystems, select which option you took here.", + widget=forms.CheckboxSelectMultiple(), required=False) + success = forms.BooleanField(help_text="Only check this if everything went fine. " \ + "If you you ran into any errors please specify them in the " \ + "comments.", required=False) + website = forms.CharField(label='', + widget=forms.TextInput(attrs={'style': 'display:none;'}), required=False) + + class Meta: + model = Test + fields = ("user_name", "user_email", "iso", "architecture", + "iso_type", "boot_type", "hardware_type", + "install_type", "source", "clock_choice", "filesystem", + "modules", "bootloader", "rollback_filesystem", + "rollback_modules", "success", "comments") + widgets = { + "modules": forms.CheckboxSelectMultiple(), + } + +def submit_test_result(request): + if request.POST: + form = TestForm(request.POST) + if form.is_valid() and request.POST['website'] == '': + test = form.save(commit=False) + test.ip_address = request.META.get("REMOTE_ADDR", None) + test.save() + return redirect('releng-test-thanks') + else: + form = TestForm() + + context = {'form': form} + return direct_to_template(request, 'releng/add.html', context) + +def calculate_option_overview(model, is_rollback=False): + option = { + 'option': model, + 'name': model._meta.verbose_name, + 'is_rollback': is_rollback, + 'values': [] + } + for value in model.objects.all(): + data = { 'value': value } + if is_rollback: + data['success'] = value.get_last_rollback_success() + data['failure'] = value.get_last_rollback_failure() + else: + data['success'] = value.get_last_success() + data['failure'] = value.get_last_failure() + option['values'].append(data) + + return option + +def test_results_overview(request): + # data structure produced: + # [ { option, name, is_rollback, values: [ { value, success, failure } ... ] } ... ] + all_options = [] + models = [ Architecture, IsoType, BootType, HardwareType, InstallType, + Source, ClockChoice, Filesystem, Module, Bootloader ] + for model in models: + all_options.append(calculate_option_overview(model)) + # now handle rollback options + for model in [ Filesystem, Module ]: + all_options.append(calculate_option_overview(model, True)) + + print all_options + context = { + 'options': all_options, + 'iso_url': settings.ISO_LIST_URL, + } + return direct_to_template(request, 'releng/results.html', context) + +def test_results_iso(request, iso_id): + iso = get_object_or_404(Iso, pk=iso_id) + test_list = iso.test_set.all() + context = { + 'iso_name': iso.name, + 'test_list': test_list + } + return direct_to_template(request, 'releng/result_list.html', context) + +def test_results_for(request, option, value): + if option not in Test._meta.get_all_field_names(): + raise Http404 + option_model = getattr(Test, option).field.rel.to + real_value = get_object_or_404(option_model, pk=value) + test_list = real_value.test_set.order_by("iso__name", "pk") + context = { + 'option': option, + 'value': real_value, + 'value_id': value, + 'test_list': test_list + } + return direct_to_template(request, 'releng/result_list.html', context) + +def submit_test_thanks(request): + return direct_to_template(request, "releng/thanks.html", None) + +# vim: set ts=4 sw=4 et: |