aboutsummaryrefslogtreecommitdiff
path: root/portal-gui/rpkigui/myrpki/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'portal-gui/rpkigui/myrpki/views.py')
-rw-r--r--portal-gui/rpkigui/myrpki/views.py256
1 files changed, 127 insertions, 129 deletions
diff --git a/portal-gui/rpkigui/myrpki/views.py b/portal-gui/rpkigui/myrpki/views.py
index be9741a5..fa9f27e3 100644
--- a/portal-gui/rpkigui/myrpki/views.py
+++ b/portal-gui/rpkigui/myrpki/views.py
@@ -26,9 +26,11 @@ from django.db import IntegrityError
from django import http
from django.views.generic.list_detail import object_list
-from rpkigui.myrpki import models, forms, glue, misc
+from rpkigui.myrpki import models, forms, glue, misc, AllocationTree
from rpkigui.myrpki.asnset import asnset
+debug = False
+
# For each type of object, we have a detail view, a create view and
# an update view. We heavily leverage the generic views, only
# adding our own idea of authorization.
@@ -60,22 +62,6 @@ def render(template, context, request):
return render_to_response(template, context,
context_instance=RequestContext(request))
-def unallocated_resources(handle, roa_asns, roa_prefixes, asns, prefixes):
- child_asns = []
- for a in asns:
- child_asns.extend(o for o in a.children.filter(allocated__isnull=True).exclude(lo__in=roa_asns) if o.hi == o.lo)
-
- child_prefixes = []
- for p in prefixes:
- child_prefixes.extend(o for o in p.children.filter(allocated__isnull=True, roa_requests__isnull=True))
-
- if child_asns or child_prefixes:
- x, y = unallocated_resources(handle, roa_asns, roa_prefixes,
- child_asns, child_prefixes)
- return asns + x, prefixes + y
- else:
- return asns, prefixes
-
@handle_required
def dashboard(request):
'''The user's dashboard.'''
@@ -90,21 +76,20 @@ def dashboard(request):
# get list of ASNs used in my ROAs
roa_asns = [r.asn for r in handle.roas.all()]
- # get list of address ranges included in ROAs
- roa_addrs = [p.prefix for r in handle.roas.all()
- for p in r.from_roa_request.all()]
-
asns=[]
- prefixes=[]
- for p in handle.parents.all():
- for c in p.resources.all():
- asns.extend(c.asn.filter(allocated__isnull=True).exclude(lo__in=roa_asns))
- prefixes.extend(c.address_range.filter(allocated__isnull=True,
- roa_requests__isnull=True))
- asns, prefixes = unallocated_resources(handle, roa_asns, roa_addrs, asns,
- prefixes)
+ for a in models.Asn.objects.filter(from_cert__parent__in=handle.parents.all()):
+ f = AllocationTree.AllocationTreeAS(a)
+ if f.unallocated():
+ asns.append(f)
- prefixes.sort(key=lambda x: x.as_resource_range().min)
+ prefixes = []
+ for p in models.AddressRange.objects.filter(from_cert__parent__in=handle.parents.all()):
+ f = AllocationTree.AllocationTreeIP.from_prefix(p)
+ if f.unallocated():
+ prefixes.append(f)
+
+ asns.sort(key=lambda x: x.range.min)
+ prefixes.sort(key=lambda x: x.range.min)
return render('myrpki/dashboard.html', { 'conf': handle, 'asns': asns,
'ars': prefixes }, request)
@@ -261,22 +246,12 @@ def child_import(request):
def get_parents_or_404(handle, obj):
'''Return the Parent object(s) that the given address range derives
from, or raise a 404 error.'''
- cert_set = top_parent(obj).from_cert.filter(parent__in=handle.parents.all())
+ cert_set = misc.top_parent(obj).from_cert.filter(parent__in=handle.parents.all())
if cert_set.count() == 0:
raise http.Http404, 'Object is not delegated from any parent'
return [c.parent for c in cert_set]
@handle_required
-def address_view(request, pk):
- handle = request.session['handle']
- obj = get_object_or_404(models.AddressRange.objects, pk=pk)
- # ensure this resource range belongs to a parent of the current conf
- parent_set = get_parents_or_404(handle, obj)
-
- return render('myrpki/prefix_view.html',
- { 'addr': obj, 'parent': parent_set }, request)
-
-@handle_required
def asn_view(request, pk):
'''view/subdivide an asn range.'''
handle = request.session['handle']
@@ -284,9 +259,11 @@ def asn_view(request, pk):
# ensure this resource range belongs to a parent of the current conf
parent_set = get_parents_or_404(handle, obj)
roas = handle.roas.filter(asn=obj.lo) # roas which contain this asn
+ unallocated = AllocationTree.AllocationTreeAS(obj).unallocated()
return render('myrpki/asn_view.html',
- { 'asn': obj, 'parent': parent_set, 'roas': roas }, request)
+ { 'asn': obj, 'parent': parent_set, 'roas': roas,
+ 'unallocated' : unallocated }, request)
@handle_required
def child_view(request, child_handle):
@@ -296,122 +273,143 @@ def child_view(request, child_handle):
return render('myrpki/child_view.html', { 'child': child }, request)
+class PrefixView(object):
+ '''Extensible view for address ranges/prefixes. This view can be
+ subclassed to add form handling for editing the prefix.'''
+
+ def __init__(self, request, pk, form_class=None):
+ self.handle = request.session['handle']
+ self.obj = get_object_or_404(models.AddressRange.objects, pk=pk)
+ # ensure this resource range belongs to a parent of the current conf
+ self.parent_set = get_parents_or_404(self.handle, self.obj)
+ self.form = None
+ self.form_class = form_class
+ self.request = request
+
+ def __call__(self, *args, **kwargs):
+ if self.request.method == 'POST':
+ resp = self.handle_post()
+ else:
+ resp = self.handle_get()
+
+ # allow get/post handlers to return a custom response
+ if resp:
+ return resp
+
+ u = AllocationTree.AllocationTreeIP.from_prefix(self.obj).unallocated()
+
+ return render('myrpki/prefix_view.html',
+ { 'addr': self.obj, 'parent': self.parent_set, 'unallocated': u, 'form': self.form },
+ self.request)
+
+ def handle_get(self):
+ '''Virtual method for extending GET handling. Default action is
+ to call the form class constructor with the prefix object.'''
+ if self.form_class:
+ self.form = self.form_class(self.obj)
+
+ def form_valid(self):
+ '''Virtual method for handling a valid form. Called by the default
+ implementation of handle_post().'''
+ pass
+
+ def handle_post(self):
+ '''Virtual method for extending POST handling. Default implementation
+ creates a form object using the form_class in the constructor and passing
+ the prefix object. If the form's is_valid() method is True, it then
+ invokes this class's form_valid() method.'''
+ resp = None
+ if self.form_class:
+ self.form = self.form_class(self.obj, self.request.POST)
+ if self.form.is_valid():
+ resp = self.form_valid()
+ return resp
+
@handle_required
-def prefix_split_view(request, pk):
- handle = request.session['handle']
- prefix = get_object_or_404(models.AddressRange.objects, pk=pk)
- # ensure this resource range belongs to a parent of the current conf
- parent_set = get_parents_or_404(handle, prefix)
+def address_view(request, pk):
+ return PrefixView(request, pk)()
- if request.method == 'POST':
- form = forms.PrefixSplitForm(prefix, request.POST)
- if form.is_valid():
- r = misc.parse_resource_range(form.cleaned_data['prefix'])
- obj = models.AddressRange(lo=str(r.min), hi=str(r.max),
- parent=prefix)
- #obj = models.AddressRange(lo=form.cleaned_data['lo'],
- # hi=form.cleaned_data['hi'], parent=prefix)
- obj.save()
- return http.HttpResponseRedirect(obj.get_absolute_url())
- else:
- form = forms.PrefixSplitForm(prefix)
+class PrefixSplitView(PrefixView):
+ '''Class for handling the prefix split form.'''
+ def form_valid(self):
+ r = misc.parse_resource_range(self.form.cleaned_data['prefix'])
+ obj = models.AddressRange(lo=str(r.min), hi=str(r.max), parent=self.obj)
+ obj.save()
+ return http.HttpResponseRedirect(obj.get_absolute_url())
- return render('myrpki/prefix_view.html', { 'form': form,
- 'addr': prefix, 'form': form, 'parent': parent_set }, request)
+@handle_required
+def prefix_split_view(request, pk):
+ return PrefixSplitView(request, pk, form_class=forms.PrefixSplitForm)()
+
+class PrefixAllocateView(PrefixView):
+ '''Class to handle the allocation to child form.'''
+ def handle_get(self):
+ self.form = forms.PrefixAllocateForm(
+ self.obj.allocated.pk if self.obj.allocated else None,
+ self.handle.children.all())
+
+ def handle_post(self):
+ self.form = forms.PrefixAllocateForm(None, self.handle.children.all(), self.request.POST)
+ if self.form.is_valid():
+ self.obj.allocated = self.form.cleaned_data['child']
+ self.obj.save()
+ glue.configure_resources(self.handle)
+ return http.HttpResponseRedirect(self.obj.get_absolute_url())
@handle_required
def prefix_allocate_view(request, pk):
- handle = request.session['handle']
- prefix = get_object_or_404(models.AddressRange.objects, pk=pk)
- # ensure this resource range belongs to a parent of the current conf
- parent_set = get_parents_or_404(handle, prefix)
-
- if request.method == 'POST':
- form = forms.PrefixAllocateForm(None, handle.children.all(), request.POST)
- if form.is_valid():
- prefix.allocated = form.cleaned_data['child']
- prefix.save()
- glue.configure_resources(handle)
- return http.HttpResponseRedirect(prefix.get_absolute_url())
- else:
- form = forms.PrefixAllocateForm(
- prefix.allocated.pk if prefix.allocated else None,
- handle.children.all())
-
- return render('myrpki/prefix_view.html', { 'form': form,
- 'addr': prefix, 'form': form, 'parent': parent_set }, request)
-
-def top_parent(prefix):
- '''Returns the topmost resource from which the specified argument derives'''
- while prefix.parent:
- prefix = prefix.parent
- return prefix
+ return PrefixAllocateView(request, pk)()
def find_roa(handle, prefix, asid):
'''Find a roa with prefixes from the same resource cert.'''
roa_set = handle.roas.filter(asn=asid)
- for c in top_parent(prefix).from_cert.all():
+ for c in misc.top_parent(prefix).from_cert.all():
for r in roa_set:
for req in r.from_roa_request.all():
- if c in top_parent(req.prefix).from_cert.all():
+ if c in misc.top_parent(req.prefix).from_cert.all():
return r
return None
def add_roa_requests(handle, prefix, asns, max_length):
for asid in asns:
- req_set = prefix.roa_requests.filter(roa__asn=asid,
- max_length=max_length)
+ if debug:
+ print 'searching for a roa for AS %d containing %s-%d' % (asid, prefix, max_length)
+ req_set = prefix.roa_requests.filter(roa__asn=asid, max_length=max_length)
if not req_set:
+ if debug:
+ print 'no roa for AS %d containing %s-%d' % (asid, prefix, max_length)
roa = find_roa(handle, prefix, asid)
if not roa:
+ if debug:
+ print 'creating new roa for AS %d containg %s-%d' % (asid, prefix, max_length)
# no roa is present for this ASN, create a new one
- roa = models.Roa.objects.create(asn=asid, conf=handle,
- active=False)
+ roa = models.Roa.objects.create(asn=asid, conf=handle, active=False)
roa.save()
- req = models.RoaRequest.objects.create(prefix=prefix, roa=roa,
- max_length=max_length)
+ req = models.RoaRequest.objects.create(prefix=prefix, roa=roa, max_length=max_length)
req.save()
+class PrefixRoaView(PrefixView):
+ '''Class for handling the ROA creation form.'''
+ def form_valid(self):
+ asns = asnset(self.form.cleaned_data['asns'])
+ add_roa_requests(self.handle, self.obj, asns, self.form.cleaned_data['max_length'])
+ glue.configure_resources(self.handle)
+ return http.HttpResponseRedirect(self.obj.get_absolute_url())
+
@handle_required
def prefix_roa_view(request, pk):
- handle = request.session['handle']
- obj = get_object_or_404(models.AddressRange.objects, pk=pk)
- # ensure this resource range belongs to a parent of the current conf
- parent_set = get_parents_or_404(handle, obj)
-
- if request.method == 'POST':
- form = forms.PrefixRoaForm(obj, request.POST)
- if form.is_valid():
- asns = asnset(form.cleaned_data['asns'])
- add_roa_requests(handle, obj, asns,
- form.cleaned_data['max_length'])
- glue.configure_resources(handle)
- return http.HttpResponseRedirect(obj.get_absolute_url())
- else:
- form = forms.PrefixRoaForm(obj)
-
- return render('myrpki/prefix_view.html', { 'form': form,
- 'addr': obj, 'form': form, 'parent': parent_set }, request)
-
+ return PrefixRoaView(request, pk, form_class=forms.PrefixRoaForm)()
+
+class PrefixDeleteView(PrefixView):
+ def form_valid(self):
+ if self.form.cleaned_data['delete']:
+ self.obj.delete()
+ return http.HttpResponseRedirect('/myrpki/')
+
@handle_required
def prefix_delete_view(request, pk):
- handle = request.session['handle']
- obj = get_object_or_404(models.AddressRange.objects, pk=pk)
- # ensure this resource range belongs to a parent of the current conf
- parent_set = get_parents_or_404(handle, obj)
-
- if request.method == 'POST':
- form = forms.PrefixDeleteForm(obj, request.POST)
- if form.is_valid():
- if form.cleaned_data['delete']:
- obj.delete()
- return http.HttpResponseRedirect('/myrpki/')
- else:
- form = forms.PrefixDeleteForm(obj)
-
- return render('myrpki/prefix_view.html', { 'form': form,
- 'addr': obj, 'form': form, 'parent': parent_set }, request)
+ return PrefixDeleteView(request, pk, form_class=forms.PrefixDeleteForm)()
@handle_required
def roa_request_delete_view(request, pk):