Adds new explicit interstitial page to download keypair.

Fixes bug 928217
Fixes bug 904470

Change-Id: Ic41d72e6bb9e51a3f0746a003a4ff2afdbb94735
This commit is contained in:
Tres Henry 2012-02-21 14:09:25 -08:00
parent 4b329ed01a
commit 2dcebb82ab
8 changed files with 87 additions and 37 deletions

View File

@ -83,7 +83,7 @@ class FloatingIpAllocate(forms.SelfHandlingForm):
% (fip.ip, data['tenant_id']))
messages.success(request,
_('Successfully allocated Floating IP "%(ip)s"\
_('Successfully allocated Floating IP "%(ip)s" \
to tenant "%(tenant)s"')
% {"ip": fip.ip, "tenant": data['tenant_id']})
except:

View File

@ -20,11 +20,9 @@
import logging
from django import http
from django import shortcuts
from django.contrib import messages
from django.core import validators
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext as _
from novaclient import exceptions as novaclient_exceptions
@ -45,14 +43,9 @@ class CreateKeypair(forms.SelfHandlingForm):
def handle(self, request, data):
try:
LOG.info('Creating keypair "%s"' % data['name'])
keypair = api.keypair_create(request, data['name'])
response = http.HttpResponse(mimetype='application/binary')
response['Content-Disposition'] = \
'attachment; filename=%s.pem' % slugify(keypair.name)
response.write(keypair.private_key)
response['Content-Length'] = str(len(response.content))
return response
return shortcuts.redirect(
'horizon:nova:access_and_security:keypairs:download',
keypair_name=data['name'])
except novaclient_exceptions.ClientException, e:
LOG.exception("ClientException in CreateKeyPair")
messages.error(request,

View File

@ -66,7 +66,16 @@ class KeyPairViewTests(test.TestCase):
self.assertTemplateUsed(res,
'nova/access_and_security/keypairs/create.html')
def test_create_keypair_post(self):
def test_download_keypair_get(self):
keypair_name = "keypair"
context = {'keypair_name': keypair_name}
url = reverse('horizon:nova:access_and_security:keypairs:download',
kwargs={'keypair_name': keypair_name})
res = self.client.get(url, context)
self.assertTemplateUsed(
res, 'nova/access_and_security/keypairs/download.html')
def test_generate_keypair_get(self):
keypair = self.keypairs.first()
keypair.private_key = "secret"
@ -75,22 +84,25 @@ class KeyPairViewTests(test.TestCase):
keypair.name).AndReturn(keypair)
self.mox.ReplayAll()
formData = {'method': 'CreateKeypair',
'name': keypair.name}
url = reverse('horizon:nova:access_and_security:keypairs:create')
res = self.client.post(url, formData)
self.assertTrue(res.has_header('Content-Disposition'))
context = {'keypair_name': keypair.name}
url = reverse('horizon:nova:access_and_security:keypairs:generate',
kwargs={'keypair_name': keypair.name})
res = self.client.get(url, context)
def test_create_keypair_exception(self):
self.assertTrue(res.has_header('content-disposition'))
def test_generate_keypair_exception(self):
keypair = self.keypairs.first()
exc = novaclient_exceptions.ClientException('clientException')
self.mox.StubOutWithMock(api, 'keypair_create')
api.keypair_create(IsA(http.HttpRequest), keypair.name).AndRaise(exc)
self.mox.ReplayAll()
formData = {'method': 'CreateKeypair',
'name': keypair.name}
url = reverse('horizon:nova:access_and_security:keypairs:create')
res = self.client.post(url, formData)
context = {'keypair_name': keypair.name}
url = reverse('horizon:nova:access_and_security:keypairs:generate',
kwargs={'keypair_name': keypair.name})
res = self.client.get(url, context)
self.assertRedirectsNoFollow(res, url)
self.assertRedirectsNoFollow(
res, reverse('horizon:nova:access_and_security:index'))

View File

@ -20,10 +20,14 @@
from django.conf.urls.defaults import patterns, url
from .views import CreateView, ImportView
from .views import CreateView, ImportView, DownloadView, GenerateView
urlpatterns = patterns('',
url(r'^create/$', CreateView.as_view(), name='create'),
url(r'^import/$', ImportView.as_view(), name='import'),
url(r'^(?P<keypair_name>[^/]+)/download/$', DownloadView.as_view(),
name='download'),
url(r'^(?P<keypair_name>[^/]+)/generate/$', GenerateView.as_view(),
name='generate'),
)

View File

@ -23,8 +23,16 @@ Views for managing Nova keypairs.
"""
import logging
from horizon import forms
from django import http
from django.core.urlresolvers import reverse
from django.template.defaultfilters import slugify
from django.views.generic import View, TemplateView
from django.utils.translation import ugettext as _
from .forms import CreateKeypair, ImportKeypair
from horizon import api
from horizon import forms
from horizon import exceptions
LOG = logging.getLogger(__name__)
@ -38,3 +46,27 @@ class CreateView(forms.ModalFormView):
class ImportView(forms.ModalFormView):
form_class = ImportKeypair
template_name = 'nova/access_and_security/keypairs/import.html'
class DownloadView(TemplateView):
def get_context_data(self, keypair_name=None):
return {'keypair_name': keypair_name}
template_name = 'nova/access_and_security/keypairs/download.html'
class GenerateView(View):
def get(self, request, keypair_name=None):
try:
keypair = api.keypair_create(request, keypair_name)
except:
redirect = reverse('horizon:nova:access_and_security:index')
exceptions.handle(self.request,
_('Unable to create keypair: %(exc)s'),
redirect=redirect)
response = http.HttpResponse(mimetype='application/binary')
response['Content-Disposition'] = \
'attachment; filename=%s.pem' % slugify(keypair.name)
response.write(keypair.private_key)
response['Content-Length'] = str(len(response.content))
return response

View File

@ -0,0 +1,21 @@
{% extends 'nova/base.html' %}
{% load i18n %}
{% block title %}{% blocktrans %}Download Keypair{% endblocktrans %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Download Keypair") %}
{% endblock page_header %}
{% block dash_main %}
<div class="modal-header">
<h3>{% blocktrans %}The keypair &quot;{{ keypair_name }}&quot; should download automatically. If not use the link below.{% endblocktrans %}</h3>
</div>
<div class="modal-body clearfix">
<a href="{% url horizon:nova:access_and_security:keypairs:generate keypair_name %}">
{% blocktrans %}Download keypair &quot;{{ keypair_name}}&quot;{% endblocktrans %}
</a>
</div>
<script type="text/javascript" charset="utf-8">
document.location = '{% url horizon:nova:access_and_security:keypairs:generate keypair_name %}';
</script>
{% endblock %}

View File

@ -848,4 +848,3 @@ form .error {
color: #b94a48;
border: 1px solid #E9B1B0;
}

View File

@ -9,17 +9,6 @@ horizon.addInitFunction(function () {
return true;
});
// TODO (tres): WTF?
$(document).on("submit", ".modal #create_keypair_form", function (e) {
var $this = $(this);
$this.closest(".modal").modal("hide");
$('.topbar').after('<div class="alert alert-block alert-info">'
+ '<p><strong>Info: </strong>The data on this page may have changed, '
+ '<a href=".">click here to refresh it</a>.</p>'
+ '</div>');
return true;
});
// Confirmation on deletion of items.
// TODO (tres): These need to be localizable or to just plain go away in favor
// of modals.