aboutsummaryrefslogtreecommitdiff
path: root/rpki/gui/app
diff options
context:
space:
mode:
Diffstat (limited to 'rpki/gui/app')
-rw-r--r--rpki/gui/app/check_expired.py43
-rw-r--r--rpki/gui/app/forms.py2
-rw-r--r--rpki/gui/app/glue.py75
-rw-r--r--rpki/gui/app/models.py37
-rwxr-xr-xrpki/gui/app/range_list.py2
-rw-r--r--rpki/gui/app/templates/app/roarequest_confirm_multi_form.html37
-rw-r--r--rpki/gui/app/templates/app/roarequest_multi_form.html11
-rw-r--r--rpki/gui/app/templates/app/route_detail.html8
-rw-r--r--rpki/gui/app/urls.py10
-rw-r--r--rpki/gui/app/views.py87
10 files changed, 106 insertions, 206 deletions
diff --git a/rpki/gui/app/check_expired.py b/rpki/gui/app/check_expired.py
index a084af79..62292e66 100644
--- a/rpki/gui/app/check_expired.py
+++ b/rpki/gui/app/check_expired.py
@@ -25,9 +25,10 @@ from rpki.gui.cacheview.models import Cert
from rpki.gui.app.models import Conf, ResourceCert, Timestamp, Alert
from rpki.gui.app.glue import list_received_resources
from rpki.irdb import Zookeeper
-from rpki.left_right import report_error_elt, list_published_objects_elt
from rpki.x509 import X509
+from rpki.left_right import version, nsmap, tag_msg, tag_list_published_objects
+from lxml.etree import Element, SubElement
from django.core.mail import send_mail
logger = logging.getLogger(__name__)
@@ -41,8 +42,8 @@ def check_cert(handle, p, errs):
The displayed object name defaults to the class name, but can be overridden
using the `object_name` argument.
-
"""
+
t = p.certificate.getNotAfter()
if t <= expire_time:
e = 'expired' if t <= now else 'will expire'
@@ -102,30 +103,26 @@ def check_expire(conf, errs):
def check_child_certs(conf, errs):
"""Fetch the list of published objects from rpkid, and inspect the issued
resource certs (uri ending in .cer).
-
"""
+
z = Zookeeper(handle=conf.handle)
- req = list_published_objects_elt.make_pdu(action="list",
- tag="list_published_objects",
- self_handle=conf.handle)
+ req = Element(tag_msg, nsmap=nsmap, type="query", version=version)
+ SubElement(req, tag_list_published_objects,
+ tag="list_published_objects", self_handle=conf.handle)
pdus = z.call_rpkid(req)
for pdu in pdus:
- if isinstance(pdu, report_error_elt):
- logger.error("rpkid reported an error: %s", pdu.error_code)
- elif isinstance(pdu, list_published_objects_elt):
- if pdu.uri.endswith('.cer'):
- cert = X509()
- cert.set(Base64=pdu.obj)
- t = cert.getNotAfter()
- if t <= expire_time:
- e = 'expired' if t <= now else 'will expire'
- errs.write("%(handle)s's rescert for Child %(child)s %(expire)s on %(date)s uri=%(uri)s subject=%(subject)s\n" % {
- 'handle': conf.handle,
- 'child': pdu.child_handle,
- 'uri': pdu.uri,
- 'subject': cert.getSubject(),
- 'expire': e,
- 'date': t})
+ if pdu.get("uri").endswith('.cer'):
+ cert = X509(Base64=pdu.text)
+ t = cert.getNotAfter()
+ if t <= expire_time:
+ e = 'expired' if t <= now else 'will expire'
+ errs.write("%(handle)s's rescert for Child %(child)s %(expire)s on %(date)s uri=%(uri)s subject=%(subject)s\n" % {
+ 'handle': conf.handle,
+ 'child': pdu.get("child_handle"),
+ 'uri': pdu.get("uri"),
+ 'subject': cert.getSubject(),
+ 'expire': e,
+ 'date': t})
class NetworkError(Exception):
@@ -139,8 +136,8 @@ def notify_expired(expire_days=14, from_email=None):
expire_days: the number of days ahead of today to warn
from_email: set the From: address for the email
-
"""
+
global expire_time # so i don't have to pass it around
global now
diff --git a/rpki/gui/app/forms.py b/rpki/gui/app/forms.py
index a1214297..f173c15d 100644
--- a/rpki/gui/app/forms.py
+++ b/rpki/gui/app/forms.py
@@ -193,7 +193,7 @@ def ROARequestFormFactory(conf):
'class': 'span1'
})
)
- protect_children = forms.BooleanField(required=False)
+ confirmed = forms.BooleanField(widget=forms.HiddenInput, required=False)
def __init__(self, *args, **kwargs):
kwargs['auto_id'] = False
diff --git a/rpki/gui/app/glue.py b/rpki/gui/app/glue.py
index a2dddb51..bfade6d8 100644
--- a/rpki/gui/app/glue.py
+++ b/rpki/gui/app/glue.py
@@ -16,7 +16,6 @@
"""
This file contains code that interfaces between the django views implementing
the portal gui and the rpki.* modules.
-
"""
from __future__ import with_statement
@@ -28,17 +27,19 @@ from datetime import datetime
from rpki.resource_set import (resource_set_as, resource_set_ipv4,
resource_set_ipv6, resource_range_ipv4,
resource_range_ipv6)
-from rpki.left_right import list_received_resources_elt, report_error_elt
from rpki.irdb.zookeeper import Zookeeper
from rpki.gui.app import models
from rpki.exceptions import BadIPResource
+from rpki.left_right import nsmap, version, tag_msg, tag_list_received_resources
+from lxml.etree import Element, SubElement
from django.contrib.auth.models import User
from django.db.transaction import commit_on_success
def ghostbuster_to_vcard(gbr):
"""Convert a GhostbusterRequest object into a vCard object."""
+
import vobject
vcard = vobject.vCard()
@@ -66,18 +67,6 @@ def ghostbuster_to_vcard(gbr):
return vcard.serialize()
-class LeftRightError(Exception):
- """Class for wrapping report_error_elt errors from Zookeeper.call_rpkid().
-
- It expects a single argument, which is the associated report_error_elt instance."""
-
- def __str__(self):
- return 'Error occurred while communicating with rpkid: handle=%s code=%s text=%s' % (
- self.args[0].self_handle,
- self.args[0].error_code,
- self.args[0].error_text)
-
-
@commit_on_success
def list_received_resources(log, conf):
"""
@@ -86,11 +75,12 @@ def list_received_resources(log, conf):
The semantics are to clear the entire table and populate with the list of
certs received. Other models should not reference the table directly with
foreign keys.
-
"""
z = Zookeeper(handle=conf.handle, disable_signal_handlers=True)
- pdus = z.call_rpkid(list_received_resources_elt.make_pdu(self_handle=conf.handle))
+ req = Element(tag_msg, nsmap=nsmap, type="query", version=version)
+ SubElement(req, tag_list_received_resources, self_handle=conf.handle)
+ pdus = z.call_rpkid(req)
# pdus is sometimes None (see https://trac.rpki.net/ticket/681)
if pdus is None:
print >>log, 'error: call_rpkid() returned None for handle %s when fetching received resources' % conf.handle
@@ -99,34 +89,27 @@ def list_received_resources(log, conf):
models.ResourceCert.objects.filter(conf=conf).delete()
for pdu in pdus:
- if isinstance(pdu, report_error_elt):
- # this will cause the db to be rolled back so the above delete()
- # won't clobber existing resources
- raise LeftRightError(pdu)
- elif isinstance(pdu, list_received_resources_elt):
- if pdu.parent_handle != conf.handle:
- parent = models.Parent.objects.get(issuer=conf,
- handle=pdu.parent_handle)
- else:
- # root cert, self-signed
- parent = None
-
- not_before = datetime.strptime(pdu.notBefore, "%Y-%m-%dT%H:%M:%SZ")
- not_after = datetime.strptime(pdu.notAfter, "%Y-%m-%dT%H:%M:%SZ")
-
- cert = models.ResourceCert.objects.create(
- conf=conf, parent=parent, not_before=not_before,
- not_after=not_after, uri=pdu.uri)
-
- for asn in resource_set_as(pdu.asn):
- cert.asn_ranges.create(min=asn.min, max=asn.max)
-
- for rng in resource_set_ipv4(pdu.ipv4):
- cert.address_ranges.create(prefix_min=rng.min,
- prefix_max=rng.max)
-
- for rng in resource_set_ipv6(pdu.ipv6):
- cert.address_ranges_v6.create(prefix_min=rng.min,
- prefix_max=rng.max)
+ if pdu.get("parent_handle") != conf.handle:
+ parent = models.Parent.objects.get(issuer=conf,
+ handle=pdu.get("parent_handle"))
else:
- print >>log, "error: unexpected pdu from rpkid type=%s" % type(pdu)
+ # root cert, self-signed
+ parent = None
+
+ not_before = datetime.strptime(pdu.get("notBefore"), "%Y-%m-%dT%H:%M:%SZ")
+ not_after = datetime.strptime(pdu.get("notAfter"), "%Y-%m-%dT%H:%M:%SZ")
+
+ cert = models.ResourceCert.objects.create(
+ conf=conf, parent=parent, not_before=not_before,
+ not_after=not_after, uri=pdu.get("uri"))
+
+ for asn in resource_set_as(pdu.get("asn")):
+ cert.asn_ranges.create(min=asn.min, max=asn.max)
+
+ for rng in resource_set_ipv4(pdu.get("ipv4")):
+ cert.address_ranges.create(prefix_min=rng.min,
+ prefix_max=rng.max)
+
+ for rng in resource_set_ipv6(pdu.get("ipv6")):
+ cert.address_ranges_v6.create(prefix_min=rng.min,
+ prefix_max=rng.max)
diff --git a/rpki/gui/app/models.py b/rpki/gui/app/models.py
index 40bdbe2c..ed32e9d2 100644
--- a/rpki/gui/app/models.py
+++ b/rpki/gui/app/models.py
@@ -18,7 +18,6 @@ __version__ = '$Id$'
from django.db import models
from django.contrib.auth.models import User
from django.core.mail import send_mail
-from django.db.models import Q
import rpki.resource_set
import rpki.exceptions
@@ -66,15 +65,6 @@ class Child(rpki.irdb.models.Child):
proxy = True
verbose_name_plural = 'children'
- @property
- def routes(self):
- "Return a list of RouteOrigin objects (potentially) originated by this child."
- query = Q()
- for r in self.address_ranges.filter(version='IPv4'):
- rng = r.as_resource_range()
- query |= Q(prefix_min__gte=rng.min, prefix_max__lte=rng.max)
- return RouteOrigin.objects.filter(query)
-
class ChildASN(rpki.irdb.models.ChildASN):
"""Proxy model for irdb ChildASN."""
@@ -131,30 +121,17 @@ class Conf(rpki.irdb.models.ResourceHolderCA):
def parents(self):
"""Simulates irdb.models.Parent.objects, but returns app.models.Parent
proxy objects.
-
"""
+
return Parent.objects.filter(issuer=self)
@property
def children(self):
"""Simulates irdb.models.Child.objects, but returns app.models.Child
proxy objects.
-
- When running rootd, we need to exclude the Child object for self.
-
"""
- return Child.objects.filter(issuer=self).exclude(handle=self.handle)
- @property
- def child_routes(self):
- """Return currently announced routes for prefixes covered by child
- sub-allocations.
- """
- query = Q()
- for pfx in ChildNet.objects.filter(child__issuer=self, version='IPv4'):
- rng = pfx.as_resource_range()
- query |= Q(prefix_min__gte=rng.min, prefix_max__lte=rng.max)
- return RouteOrigin.objects.filter(query)
+ return Child.objects.filter(issuer=self)
@property
def ghostbusters(self):
@@ -172,8 +149,8 @@ class Conf(rpki.irdb.models.ResourceHolderCA):
def routes(self):
"""Return all IPv4 routes covered by RPKI certs issued to this resource
holder.
-
"""
+
# build a Q filter to select all RouteOrigin objects covered by
# prefixes in the resource holder's certificates
prefixes = ResourceRangeAddressV4.objects.filter(cert__conf=self)
@@ -190,8 +167,8 @@ class Conf(rpki.irdb.models.ResourceHolderCA):
def routes_v6(self):
"""Return all IPv6 routes covered by RPKI certs issued to this resource
holder.
-
"""
+
# build a Q filter to select all RouteOrigin objects covered by
# prefixes in the resource holder's certificates
prefixes = ResourceRangeAddressV6.objects.filter(cert__conf=self)
@@ -206,6 +183,7 @@ class Conf(rpki.irdb.models.ResourceHolderCA):
def send_alert(self, subject, message, from_email, severity=Alert.INFO):
"""Store an alert for this resource holder."""
+
self.alerts.create(subject=subject, text=message, severity=severity)
send_mail(
@@ -221,8 +199,8 @@ class Conf(rpki.irdb.models.ResourceHolderCA):
Contact emails are extract from any ghostbuster requests, and any
linked user accounts.
-
"""
+
notify_emails = [gbr.email_address for gbr in self.ghostbusters if gbr.email_address]
notify_emails.extend(
[acl.user.email for acl in ConfACL.objects.filter(conf=self) if acl.user.email]
@@ -247,7 +225,6 @@ class ResourceCert(models.Model):
"""Represents a resource certificate.
This model is used to cache the output of <list_received_resources/>.
-
"""
# Handle to which this cert was issued
@@ -275,6 +252,7 @@ class ResourceCert(models.Model):
def get_cert_chain(self):
"""Return a list containing the complete certificate chain for this
certificate."""
+
cert = self
x = [cert]
while cert.issuer:
@@ -448,7 +426,6 @@ class RouteOriginV6(rpki.gui.routeview.models.RouteOriginV6):
class ConfACL(models.Model):
"""Stores access control for which users are allowed to manage a given
resource handle.
-
"""
conf = models.ForeignKey(Conf)
diff --git a/rpki/gui/app/range_list.py b/rpki/gui/app/range_list.py
index 21fd1f29..5cb4f5e4 100755
--- a/rpki/gui/app/range_list.py
+++ b/rpki/gui/app/range_list.py
@@ -70,6 +70,7 @@ class RangeList(list):
def difference(self, other):
"""Return a RangeList object which contains ranges in this object which
are not in "other"."""
+
it = iter(other)
try:
@@ -85,6 +86,7 @@ class RangeList(list):
def V(v):
"""convert the integer value to the appropriate type for this
range"""
+
return x.__class__.datum_type(v)
try:
diff --git a/rpki/gui/app/templates/app/roarequest_confirm_multi_form.html b/rpki/gui/app/templates/app/roarequest_confirm_multi_form.html
index d1d8171f..4a06a4aa 100644
--- a/rpki/gui/app/templates/app/roarequest_confirm_multi_form.html
+++ b/rpki/gui/app/templates/app/roarequest_confirm_multi_form.html
@@ -1,4 +1,5 @@
{% extends "app/app_base.html" %}
+{% load url from future %}
{% load app_extras %}
{% block content %}
@@ -8,20 +9,17 @@
<div class='row-fluid'>
<div class='span6'>
- <div class='alert'>
- <strong>Please confirm</strong> that you would like to create the following ROA(s).
+ <div class='alert alert-block-message alert-warning'>
+ <p><strong>Please confirm</strong> that you would like to create the following ROA(s).
The accompanying table indicates how the validation status may change as a result.
</div>
<table class='table table-condensed table-striped'>
- <thead>
- <tr>
- <th>Prefix</th>
- <th>Max Length</th>
- <th>AS</th>
- </tr>
- </thead>
- <tbody>
+ <tr>
+ <th>Prefix</th>
+ <th>Max Length</th>
+ <th>AS</th>
+ </tr>
{% for roa in roas %}
<tr>
<td>{{ roa.prefix }}</td>
@@ -29,7 +27,6 @@
<td>{{ roa.asn }}</td>
</tr>
{% endfor %}
- </tbody>
</table>
<form method='POST' action='{% url "rpki.gui.app.views.roa_create_multi_confirm" %}'>
@@ -50,22 +47,18 @@
<h2>Matched Routes</h2>
<table class='table table-striped table-condensed'>
- <thead>
- <tr>
- <th>Prefix</th>
- <th>Origin AS</th>
- <th>Validation Status</th>
- </tr>
- </thead>
- <tbody>
+ <tr>
+ <th>Prefix</th>
+ <th>Origin AS</th>
+ <th>Validation Status</th>
+ </tr>
{% for r in routes %}
<tr>
- <td>{{ r.get_prefix_display }}</td>
- <td>{{ r.asn }}</td>
+ <td>{{ r.get_prefix_display }}</td>
+ <td>{{ r.asn }}</td>
<td>{% validity_label r.newstatus %}</td>
</tr>
{% endfor %}
- </tbody>
</table>
</div>
diff --git a/rpki/gui/app/templates/app/roarequest_multi_form.html b/rpki/gui/app/templates/app/roarequest_multi_form.html
index ed2135ed..0fbc49ae 100644
--- a/rpki/gui/app/templates/app/roarequest_multi_form.html
+++ b/rpki/gui/app/templates/app/roarequest_multi_form.html
@@ -1,28 +1,27 @@
{% extends "app/app_base.html" %}
+{% load url from future %}
{% block content %}
<div class='page-title'>
<h1>Create ROAs</h1>
</div>
-<form class='form-inline' method='POST' action='{{ request.get_full_path }}'>
+<form method='POST' action='{{ request.get_full_path }}'>
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
-
+ <div class="controls controls-row">
{{ form.prefix }}
{{ form.max_prefixlen }}
{{ form.asn }}
- <label class="checkbox" title='create additional ROAs for child routes'>{{ form.protect_children }} Protect children</label>
-
{# <label class="checkbox inline span1">{{ form.DELETE }} Delete</label> #}
{% if form.errors %}<span class="help-inline">{{ form.errors }}</span>{% endif %}
{% if form.non_field_errors %}<span class="help-inline">{{ form.non_field_errors }}</span>{% endif %}
-
+ </div>
{% endfor %}
<div class="form-actions">
- <button class='btn btn-primary' type='submit'>Preview</button>
+ <input class="btn" type="submit" value="Preview">
<a class="btn" href="{% url "rpki.gui.app.views.dashboard" %}">Cancel</a>
</div>
</form>
diff --git a/rpki/gui/app/templates/app/route_detail.html b/rpki/gui/app/templates/app/route_detail.html
index 8bd744df..84add4a8 100644
--- a/rpki/gui/app/templates/app/route_detail.html
+++ b/rpki/gui/app/templates/app/route_detail.html
@@ -42,15 +42,13 @@
</thead>
<tbody>
{% for pfx in roa_prefixes %}
- {% for roa in pfx.roas.all %}
<tr>
<td>{{ pfx.as_resource_range }}</td>
<td>{{ pfx.max_length }}</td>
- <td>{{ roa.asid }}</td>
- <td>{{ roa.not_after }}</td>
- <td>{{ roa.repo.uri }}</td>
+ <td>{{ pfx.roas.all.0.asid }}</td>
+ <td>{{ pfx.roas.all.0.not_after }}</td>
+ <td>{{ pfx.roas.all.0.repo.uri }}</td>
</tr>
- {% endfor %}
{% endfor %}
</tbody>
</table>
diff --git a/rpki/gui/app/urls.py b/rpki/gui/app/urls.py
index 81c9b127..f595ea8f 100644
--- a/rpki/gui/app/urls.py
+++ b/rpki/gui/app/urls.py
@@ -88,14 +88,12 @@ urlpatterns = patterns(
#{'post_reset_redirect' : '/user/password/reset/done/'},
{'extra_context': {'form_title': 'Password Reset'}},
name="password_reset"),
- url(r'^user/password/reset/done/$',
- 'django.contrib.auth.views.password_reset_done',
- name='password_reset_done'),
+ (r'^user/password/reset/done/$',
+ 'django.contrib.auth.views.password_reset_done'),
url(r'^user/password/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
'django.contrib.auth.views.password_reset_confirm',
#{'post_reset_redirect' : '/user/password/done/'},
name="password_reset_confirm"),
- url(r'^user/password/done/$',
- 'django.contrib.auth.views.password_reset_complete',
- name='password_reset_complete'),
+ (r'^user/password/done/$',
+ 'django.contrib.auth.views.password_reset_complete'),
)
diff --git a/rpki/gui/app/views.py b/rpki/gui/app/views.py
index bf152f8e..dfd36dbb 100644
--- a/rpki/gui/app/views.py
+++ b/rpki/gui/app/views.py
@@ -27,7 +27,6 @@ from tempfile import NamedTemporaryFile
import cStringIO
import csv
import logging
-import lxml.etree
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
@@ -39,8 +38,8 @@ from django.contrib.auth.models import User
from django.views.generic import DetailView, ListView, DeleteView, FormView
from django.core.paginator import Paginator, InvalidPage
from django.forms.formsets import formset_factory, BaseFormSet
+import django.db.models
from django.contrib import messages
-from django.db.models import Q
from rpki.irdb import Zookeeper, ChildASN, ChildNet, ROARequestPrefix
from rpki.gui.app import models, forms, glue, range_list
@@ -147,28 +146,19 @@ def generic_import(request, queryset, configure, form_class=None,
# expects it.
if handle == '':
handle = None
- try:
- # configure_repository returns None, so can't use tuple expansion
- # here. Unpack the tuple below if post_import_redirect is None.
- r = configure(z, tmpf.name, handle)
- except lxml.etree.XMLSyntaxError as e:
- logger.exception('caught XMLSyntaxError while parsing uploaded file')
- messages.error(
- request,
- 'The uploaded file has an invalid XML syntax'
- )
+ # configure_repository returns None, so can't use tuple expansion
+ # here. Unpack the tuple below if post_import_redirect is None.
+ r = configure(z, tmpf.name, handle)
+ # force rpkid run now
+ z.synchronize_ca(poke=True)
+ os.remove(tmpf.name)
+ if post_import_redirect:
+ url = post_import_redirect
else:
- # force rpkid run now
- z.synchronize_ca(poke=True)
- if post_import_redirect:
- url = post_import_redirect
- else:
- _, handle = r
- url = queryset.get(issuer=conf,
- handle=handle).get_absolute_url()
- return http.HttpResponseRedirect(url)
- finally:
- os.remove(tmpf.name)
+ _, handle = r
+ url = queryset.get(issuer=conf,
+ handle=handle).get_absolute_url()
+ return http.HttpResponseRedirect(url)
else:
form = form_class()
@@ -632,6 +622,7 @@ def get_covered_routes(rng, max_prefixlen, asn):
return routes
+
@handle_required
def roa_create(request):
"""Present the user with a form to create a ROA.
@@ -717,58 +708,20 @@ def roa_create_multi(request):
formset = formset_factory(forms.ROARequestFormFactory(conf), extra=extra)(initial=init)
elif request.method == 'POST':
formset = formset_factory(forms.ROARequestFormFactory(conf), extra=0)(request.POST, request.FILES)
- # We need to check .has_changed() because .is_valid() will return true
- # if the user clicks the Preview button without filling in the blanks
- # in the ROA form, leaving the form invalid from this view's POV.
- if formset.has_changed() and formset.is_valid():
+ if formset.is_valid():
routes = []
v = []
- query = Q() # for matching routes
- roas = []
for form in formset:
asn = form.cleaned_data['asn']
rng = resource_range_ip.parse_str(form.cleaned_data['prefix'])
max_prefixlen = int(form.cleaned_data['max_prefixlen'])
- protect_children = form.cleaned_data['protect_children']
-
- roas.append((rng, max_prefixlen, asn, protect_children))
+ # FIXME: This won't do the right thing in the event that a
+ # route is covered by multiple ROAs created in the form.
+ # You will see duplicate entries, each with a potentially
+ # different validation status.
+ routes.extend(get_covered_routes(rng, max_prefixlen, asn))
v.append({'prefix': str(rng), 'max_prefixlen': max_prefixlen,
'asn': asn})
-
- query |= Q(prefix_min__gte=rng.min, prefix_max__lte=rng.max)
-
- for rt in RouteOrigin.objects.filter(query):
- status = rt.status # cache the value
- newstatus = status
- if status == 'unknown':
- # possible change to valid or invalid
- for rng, max_prefixlen, asn, protect in roas:
- if rng.min <= rt.prefix_min and rng.max >= rt.prefix_max:
- # this route is covered
- if asn == rt.asn and rt.prefixlen <= max_prefixlen:
- newstatus = 'valid'
- break # no need to continue for this route
- else:
- newstatus = 'invalid'
- elif status == 'invalid':
- # possible change to valid
- for rng, max_prefixlen, asn, protect in roas:
- if rng.min <= rt.prefix_min and rng.max >= rt.prefix_max:
- # this route is covered
- if asn == rt.asn and rt.prefixlen <= max_prefixlen:
- newstatus = 'valid'
- break # no need to continue for this route
-
- if status != newstatus:
- if protect_children and newstatus == 'invalid' and conf.child_routes.filter(pk=rt.pk).exists():
- rng = rt.as_resource_range()
- v.append({'prefix': str(rng),
- 'max_prefixlen': rng.prefixlen,
- 'asn': rt.asn})
- newstatus = 'valid'
- rt.newstatus = newstatus # I"M A MUHNKAY!!!
- routes.append(rt)
-
# if there were no rows, skip the confirmation step
if v:
formset = formset_factory(forms.ROARequestConfirm, extra=0)(initial=v)