aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpki/async.py8
-rw-r--r--rpki/gui/app/forms.py5
-rw-r--r--rpki/gui/app/glue.py2
-rw-r--r--rpki/gui/app/templates/app/roarequest_multi_form.html2
-rw-r--r--rpki/gui/app/views.py132
-rw-r--r--rpki/irdb/zookeeper.py4
6 files changed, 102 insertions, 51 deletions
diff --git a/rpki/async.py b/rpki/async.py
index f2abd05d..5b3d35b1 100644
--- a/rpki/async.py
+++ b/rpki/async.py
@@ -352,8 +352,9 @@ class sync_wrapper(object):
err = None
fin = False
- def __init__(self, func):
+ def __init__(self, func, disable_signal_handlers = False):
self.func = func
+ self.disable_signal_handlers = disable_signal_handlers
def cb(self, res = None):
"""
@@ -389,7 +390,10 @@ class sync_wrapper(object):
self.eb(e)
event_defer(thunk)
- event_loop()
+ if self.disable_signal_handlers:
+ event_loop(catch_signals = ())
+ else:
+ event_loop()
if not self.fin:
logger.warning("%r event_loop terminated without callback or errback", self)
if self.err is None:
diff --git a/rpki/gui/app/forms.py b/rpki/gui/app/forms.py
index fffac1be..f173c15d 100644
--- a/rpki/gui/app/forms.py
+++ b/rpki/gui/app/forms.py
@@ -106,6 +106,11 @@ class ImportClientForm(forms.Form):
class ImportCSVForm(forms.Form):
csv = forms.FileField(label='CSV file')
+ ignore_missing_children = forms.BooleanField(
+ label='Ignore missing children',
+ help_text='Discard data for children that are not currently in the IRDB',
+ required=False
+ )
class UserCreateForm(forms.Form):
diff --git a/rpki/gui/app/glue.py b/rpki/gui/app/glue.py
index 8a008447..bfade6d8 100644
--- a/rpki/gui/app/glue.py
+++ b/rpki/gui/app/glue.py
@@ -77,7 +77,7 @@ def list_received_resources(log, conf):
foreign keys.
"""
- z = Zookeeper(handle=conf.handle)
+ z = Zookeeper(handle=conf.handle, disable_signal_handlers=True)
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)
diff --git a/rpki/gui/app/templates/app/roarequest_multi_form.html b/rpki/gui/app/templates/app/roarequest_multi_form.html
index 06d07943..0fbc49ae 100644
--- a/rpki/gui/app/templates/app/roarequest_multi_form.html
+++ b/rpki/gui/app/templates/app/roarequest_multi_form.html
@@ -14,7 +14,7 @@
{{ form.prefix }}
{{ form.max_prefixlen }}
{{ form.asn }}
- <label class="checkbox inline span1">{{ form.DELETE }} Delete</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>
diff --git a/rpki/gui/app/views.py b/rpki/gui/app/views.py
index a9c038f5..dfd36dbb 100644
--- a/rpki/gui/app/views.py
+++ b/rpki/gui/app/views.py
@@ -47,6 +47,7 @@ from rpki.resource_set import (resource_range_as, resource_range_ip,
roa_prefix_ipv4)
from rpki import sundial
import rpki.exceptions
+import rpki.csv_utils
from rpki.gui.cacheview.models import ROA
from rpki.gui.routeview.models import RouteOrigin
@@ -324,12 +325,26 @@ def import_asns(request):
f = NamedTemporaryFile(prefix='asns', suffix='.csv', delete=False)
f.write(request.FILES['csv'].read())
f.close()
- z = Zookeeper(handle=conf.handle)
- z.load_asns(f.name)
- z.run_rpkid_now()
- os.unlink(f.name)
- messages.success(request, 'Successfully imported AS delgations from CSV file.')
- return redirect(dashboard)
+ z = Zookeeper(handle=conf.handle, disable_signal_handlers=True)
+ try:
+ z.load_asns(
+ f.name,
+ ignore_missing_children=form.cleaned_data['ignore_missing_children']
+ )
+ except rpki.irdb.models.Child.DoesNotExist:
+ messages.error(
+ request,
+ 'CSV file contains children not found in the IRDB'
+ )
+ except rpki.csv_utils.BadCSVSyntax as e:
+ messages.error(request,
+ 'CSV file has an invalid syntax: %s' % (e,))
+ else:
+ z.run_rpkid_now()
+ messages.success(request, 'Successfully imported AS delgations from CSV file.')
+ return redirect(dashboard)
+ finally:
+ os.unlink(f.name)
else:
form = forms.ImportCSVForm()
return render(request, 'app/import_resource_form.html', {
@@ -359,12 +374,23 @@ def import_prefixes(request):
f = NamedTemporaryFile(prefix='prefixes', suffix='.csv', delete=False)
f.write(request.FILES['csv'].read())
f.close()
- z = Zookeeper(handle=conf.handle)
- z.load_prefixes(f.name)
- z.run_rpkid_now()
- os.unlink(f.name)
- messages.success(request, 'Successfully imported prefix delegations from CSV file.')
- return redirect(dashboard)
+ z = Zookeeper(handle=conf.handle, disable_signal_handlers=True)
+ try:
+ z.load_prefixes(
+ f.name,
+ ignore_missing_children=form.cleaned_data['ignore_missing_children']
+ )
+ except rpki.irdb.models.Child.DoesNotExist:
+ messages.error(request, 'CSV file contains children not found in the IRDB')
+ except rpki.csv_utils.BadCSVSyntax as e:
+ messages.error(request,
+ 'CSV file has an invalid syntax: %s' % (e,))
+ else:
+ z.run_rpkid_now()
+ messages.success(request, 'Successfully imported AS delgations from CSV file.')
+ return redirect(dashboard)
+ finally:
+ os.unlink(f.name)
else:
form = forms.ImportCSVForm()
return render(request, 'app/import_resource_form.html', {
@@ -437,7 +463,11 @@ def child_add_prefix(request, pk):
version = 'IPv%d' % r.version
child.address_ranges.create(start_ip=str(r.min), end_ip=str(r.max),
version=version)
- Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now()
+ Zookeeper(
+ handle=conf.handle,
+ logstream=logstream,
+ disable_signal_handlers=True
+ ).run_rpkid_now()
return http.HttpResponseRedirect(child.get_absolute_url())
else:
form = forms.AddNetForm(child=child)
@@ -456,7 +486,11 @@ def child_add_asn(request, pk):
asns = form.cleaned_data.get('asns')
r = resource_range_as.parse_str(asns)
child.asns.create(start_as=r.min, end_as=r.max)
- Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now()
+ Zookeeper(
+ handle=conf.handle,
+ logstream=logstream,
+ disable_signal_handlers=True
+ ).run_rpkid_now()
return http.HttpResponseRedirect(child.get_absolute_url())
else:
form = forms.AddASNForm(child=child)
@@ -486,7 +520,11 @@ def child_edit(request, pk):
# remove AS & prefixes that are not selected in the form
models.ChildASN.objects.filter(child=child).exclude(pk__in=form.cleaned_data.get('as_ranges')).delete()
models.ChildNet.objects.filter(child=child).exclude(pk__in=form.cleaned_data.get('address_ranges')).delete()
- Zookeeper(handle=conf.handle, logstream=log).run_rpkid_now()
+ Zookeeper(
+ handle=conf.handle,
+ logstream=logstream,
+ disable_signal_handlers=True
+ ).run_rpkid_now()
return http.HttpResponseRedirect(child.get_absolute_url())
else:
form = form_class(initial={
@@ -666,27 +704,24 @@ def roa_create_multi(request):
v = []
rng.chop_into_prefixes(v)
init.extend([{'asn': asn, 'prefix': str(p)} for p in v])
- formset = formset_factory(forms.ROARequestFormFactory(conf), can_delete=True)(initial=init)
+ extra = 0 if init else 1
+ formset = formset_factory(forms.ROARequestFormFactory(conf), extra=extra)(initial=init)
elif request.method == 'POST':
- formset = formset_factory(forms.ROARequestFormFactory(conf), extra=0, can_delete=True)(request.POST, request.FILES)
+ formset = formset_factory(forms.ROARequestFormFactory(conf), extra=0)(request.POST, request.FILES)
if formset.is_valid():
routes = []
v = []
- # as of Django 1.4.5 we still can't use formset.cleaned_data
- # because deleted forms are not excluded, which causes an
- # AttributeError to be raised.
for form in formset:
- if hasattr(form, 'cleaned_data') and form.cleaned_data: # exclude empty forms
- asn = form.cleaned_data.get('asn')
- rng = resource_range_ip.parse_str(form.cleaned_data.get('prefix'))
- max_prefixlen = int(form.cleaned_data.get('max_prefixlen'))
- # 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})
+ asn = form.cleaned_data['asn']
+ rng = resource_range_ip.parse_str(form.cleaned_data['prefix'])
+ max_prefixlen = int(form.cleaned_data['max_prefixlen'])
+ # 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})
# if there were no rows, skip the confirmation step
if v:
formset = formset_factory(forms.ROARequestConfirm, extra=0)(initial=v)
@@ -718,7 +753,7 @@ def roa_create_confirm(request):
roa.prefixes.create(version=v, prefix=str(rng.min),
prefixlen=rng.prefixlen(),
max_prefixlen=max_prefixlen)
- Zookeeper(handle=conf.handle, logstream=log).run_rpkid_now()
+ Zookeeper(handle=conf.handle, logstream=log, disable_signal_handlers=True).run_rpkid_now()
return http.HttpResponseRedirect(reverse(dashboard))
# What should happen when the submission form isn't valid? For now
# just fall through and redirect back to the ROA creation form
@@ -748,7 +783,7 @@ def roa_create_multi_confirm(request):
roa.prefixes.create(version=v, prefix=str(rng.min),
prefixlen=rng.prefixlen(),
max_prefixlen=max_prefixlen)
- Zookeeper(handle=conf.handle, logstream=log).run_rpkid_now()
+ Zookeeper(handle=conf.handle, logstream=log, disable_signal_handlers=True).run_rpkid_now()
return redirect(dashboard)
# What should happen when the submission form isn't valid? For now
# just fall through and redirect back to the ROA creation form
@@ -768,7 +803,7 @@ def roa_delete(request, pk):
roa = get_object_or_404(conf.roas, pk=pk)
if request.method == 'POST':
roa.delete()
- Zookeeper(handle=conf.handle).run_rpkid_now()
+ Zookeeper(handle=conf.handle, disable_signal_handlers=True).run_rpkid_now()
return redirect(reverse(dashboard))
### Process GET ###
@@ -825,12 +860,19 @@ def roa_import(request):
tmp = tempfile.NamedTemporaryFile(suffix='.csv', prefix='roas', delete=False)
tmp.write(request.FILES['csv'].read())
tmp.close()
- z = Zookeeper(handle=request.session['handle'])
- z.load_roa_requests(tmp.name)
- z.run_rpkid_now()
- os.unlink(tmp.name)
- messages.success(request, 'Successfully imported ROAs.')
- return redirect(dashboard)
+ z = Zookeeper(handle=request.session['handle'],
+ disable_signal_handlers=True)
+ try:
+ z.load_roa_requests(tmp.name)
+ except rpki.csv_utils.BadCSVSyntax as e:
+ messages.error(request,
+ 'CSV has bad syntax: %s' % (e,))
+ else:
+ z.run_rpkid_now()
+ messages.success(request, 'Successfully imported ROAs.')
+ return redirect(dashboard)
+ finally:
+ os.unlink(tmp.name)
else:
form = forms.ImportCSVForm()
return render(request, 'app/import_resource_form.html', {
@@ -870,7 +912,7 @@ def ghostbuster_delete(request, pk):
form = forms.Empty(request.POST, request.FILES)
if form.is_valid():
obj.delete()
- Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now()
+ Zookeeper(handle=conf.handle, logstream=logstream, disable_signal_handlers=True).run_rpkid_now()
return http.HttpResponseRedirect(reverse(dashboard))
else:
form = forms.Empty(request.POST, request.FILES)
@@ -892,7 +934,7 @@ def ghostbuster_create(request):
obj = form.save(commit=False)
obj.vcard = glue.ghostbuster_to_vcard(obj)
obj.save()
- Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now()
+ Zookeeper(handle=conf.handle, logstream=logstream, disable_signal_handlers=True).run_rpkid_now()
return http.HttpResponseRedirect(reverse(dashboard))
else:
form = forms.GhostbusterRequestForm(conf=conf)
@@ -912,7 +954,7 @@ def ghostbuster_edit(request, pk):
obj = form.save(commit=False)
obj.vcard = glue.ghostbuster_to_vcard(obj)
obj.save()
- Zookeeper(handle=conf.handle, logstream=logstream).run_rpkid_now()
+ Zookeeper(handle=conf.handle, logstream=logstream, disable_signal_handlers=True).run_rpkid_now()
return http.HttpResponseRedirect(reverse(dashboard))
else:
form = forms.GhostbusterRequestForm(conf=conf, instance=obj)
@@ -1356,7 +1398,7 @@ class RouterDeleteView(DeleteView):
def delete(self, request, *args, **kwargs):
# override the delete hook so that we can nudge rpkid after the object is gone
r = super(RouterDeleteView, self).delete(request, *args, **kwargs)
- Zookeeper(handle=request.session['handle']).run_rpkid_now()
+ Zookeeper(handle=request.session['handle'], disable_signal_handlers=True).run_rpkid_now()
return r
@@ -1375,7 +1417,7 @@ class RouterImportView(FormView):
delete=False)
tmpf.write(form.cleaned_data['xml'].read())
tmpf.close()
- z = Zookeeper(handle=conf.handle)
+ z = Zookeeper(handle=conf.handle, disable_signal_handlers=True)
z.add_router_certificate_request(tmpf.name)
z.run_rpkid_now()
os.remove(tmpf.name)
diff --git a/rpki/irdb/zookeeper.py b/rpki/irdb/zookeeper.py
index bcdfaf7e..9a843a4e 100644
--- a/rpki/irdb/zookeeper.py
+++ b/rpki/irdb/zookeeper.py
@@ -192,7 +192,7 @@ class Zookeeper(object):
show_xml = None
- def __init__(self, cfg = None, handle = None, logstream = None):
+ def __init__(self, cfg = None, handle = None, logstream = None, disable_signal_handlers = False):
if cfg is None:
cfg = rpki.config.parser()
@@ -203,6 +203,7 @@ class Zookeeper(object):
self.cfg = cfg
self.logstream = logstream
+ self.disable_signal_handlers = disable_signal_handlers
self.run_rpkid = cfg.getboolean("run_rpkid", section = myrpki_section)
self.run_pubd = cfg.getboolean("run_pubd", section = myrpki_section)
@@ -1066,7 +1067,6 @@ class Zookeeper(object):
if not suppress_error_check:
self.check_error_report(r_msg)
-
return r_msg