Adds new explicit interstitial page to download keypair.
Fixes bug 928217 Fixes bug 904470 Change-Id: Ic41d72e6bb9e51a3f0746a003a4ff2afdbb94735
This commit is contained in:
parent
4b329ed01a
commit
2dcebb82ab
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "{{ keypair_name }}" 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 "{{ keypair_name}}"{% endblocktrans %}
|
||||
</a>
|
||||
</div>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
document.location = '{% url horizon:nova:access_and_security:keypairs:generate keypair_name %}';
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -848,4 +848,3 @@ form .error {
|
|||
color: #b94a48;
|
||||
border: 1px solid #E9B1B0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue