Skip to content

Commit

Permalink
Adds new explicit interstitial page to download keypair.
Browse files Browse the repository at this point in the history
Fixes bug 928217
Fixes bug 904470

Change-Id: Ic41d72e6bb9e51a3f0746a003a4ff2afdbb94735
  • Loading branch information
treshenry committed Feb 22, 2012
1 parent 4b329ed commit 2dcebb8
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 37 deletions.
Expand Up @@ -83,7 +83,7 @@ def handle(self, request, data):
% (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:
Expand Down
Expand Up @@ -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

Expand All @@ -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,
Expand Down
Expand Up @@ -66,7 +66,16 @@ def test_create_keypair_get(self):
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"

Expand All @@ -75,22 +84,25 @@ def test_create_keypair_post(self):
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'))
Expand Up @@ -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'),
)
Expand Up @@ -23,8 +23,16 @@
"""
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__)
Expand All @@ -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 &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 %}
Expand Up @@ -848,4 +848,3 @@ form .error {
color: #b94a48;
border: 1px solid #E9B1B0;
}

11 changes: 0 additions & 11 deletions openstack-dashboard/dashboard/static/dashboard/js/forms.js
Expand Up @@ -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.
Expand Down

0 comments on commit 2dcebb8

Please sign in to comment.