Implementing Floating IP Pools for Horizon
- vishy's nova branch: https://review.openstack.org/#change,2892 - jakedahn's novaclient branch: https://review.openstack.org/#change,2917 Change-Id: I41fb7359e841cbe5921db864dd4e754e9fe0874d
This commit is contained in:
parent
ad36c057f4
commit
29b70fbf92
|
@ -5,6 +5,7 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
@ -45,8 +46,13 @@ class Flavor(APIResourceWrapper):
|
|||
|
||||
|
||||
class FloatingIp(APIResourceWrapper):
|
||||
"""Simple wrapper for floating ip pools"""
|
||||
_attrs = ['ip', 'fixed_ip', 'instance_id', 'id', 'pool']
|
||||
|
||||
|
||||
class FloatingIpPool(APIResourceWrapper):
|
||||
"""Simple wrapper for floating ips"""
|
||||
_attrs = ['ip', 'fixed_ip', 'instance_id', 'id']
|
||||
_attrs = ['name']
|
||||
|
||||
|
||||
class KeyPair(APIResourceWrapper):
|
||||
|
@ -179,6 +185,13 @@ def tenant_floating_ip_list(request):
|
|||
return [FloatingIp(ip) for ip in novaclient(request).floating_ips.list()]
|
||||
|
||||
|
||||
def floating_ip_pools_list(request):
|
||||
"""
|
||||
Fetches a list of all floating ip pools.
|
||||
"""
|
||||
return [FloatingIpPool(pool)
|
||||
for pool in novaclient(request).floating_ip_pools.list()]
|
||||
|
||||
def tenant_floating_ip_get(request, floating_ip_id):
|
||||
"""
|
||||
Fetches a floating ip.
|
||||
|
@ -186,11 +199,12 @@ def tenant_floating_ip_get(request, floating_ip_id):
|
|||
return novaclient(request).floating_ips.get(floating_ip_id)
|
||||
|
||||
|
||||
def tenant_floating_ip_allocate(request):
|
||||
def tenant_floating_ip_allocate(request, pool=None):
|
||||
"""
|
||||
Allocates a floating ip to tenant.
|
||||
Optionally you may provide a pool for which you would like the IP.
|
||||
"""
|
||||
return novaclient(request).floating_ips.create()
|
||||
return novaclient(request).floating_ips.create(pool=pool)
|
||||
|
||||
|
||||
def tenant_floating_ip_release(request, floating_ip_id):
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
@ -26,6 +27,7 @@ from django.utils.translation import ugettext as _
|
|||
from novaclient import exceptions as novaclient_exceptions
|
||||
|
||||
from horizon import api
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
|
||||
|
||||
|
@ -60,3 +62,29 @@ class FloatingIpAssociate(forms.SelfHandlingForm):
|
|||
LOG.exception("ClientException in FloatingIpAssociate")
|
||||
messages.error(request, _('Error associating Floating IP: %s') % e)
|
||||
return shortcuts.redirect('horizon:nova:access_and_security:index')
|
||||
|
||||
|
||||
class FloatingIpAllocate(forms.SelfHandlingForm):
|
||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
||||
pool = forms.ChoiceField()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FloatingIpAllocate, self).__init__(*args, **kwargs)
|
||||
floating_pool_list = kwargs.get('initial', {}).get('pool_list', [])
|
||||
self.fields['pool'].choices = floating_pool_list
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
fip = api.tenant_floating_ip_allocate(request,
|
||||
pool=data.get('pool', None))
|
||||
LOG.info('Allocating Floating IP "%s" to tenant "%s"'
|
||||
% (fip.ip, data['tenant_id']))
|
||||
|
||||
messages.success(request,
|
||||
_('Successfully allocated Floating IP "%(ip)s"\
|
||||
to tenant "%(tenant)s"')
|
||||
% {"ip": fip.ip, "tenant": data['tenant_id']})
|
||||
except:
|
||||
exceptions.handle(request, _('Unable to allocate Floating IP.'))
|
||||
return shortcuts.redirect(
|
||||
'horizon:nova:access_and_security:index')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
@ -28,25 +29,13 @@ from horizon import tables
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AllocateIP(tables.Action):
|
||||
class AllocateIP(tables.LinkAction):
|
||||
name = "allocate"
|
||||
verbose_name = _("Allocate IP To Tenant")
|
||||
requires_input = False
|
||||
attrs = {"class": "ajax-modal btn primary small"}
|
||||
url = "horizon:nova:access_and_security:floating_ips:allocate"
|
||||
|
||||
def single(self, data_table, request, *args):
|
||||
tenant_id = request.user.tenant_id
|
||||
try:
|
||||
fip = api.tenant_floating_ip_allocate(request)
|
||||
LOG.info('Allocating Floating IP "%s" to tenant "%s".'
|
||||
% (fip.ip, tenant_id))
|
||||
messages.success(request, _('Successfully allocated Floating IP '
|
||||
'"%(ip)s" to tenant "%(tenant)s".')
|
||||
% {"ip": fip.ip, "tenant": tenant_id})
|
||||
except novaclient_exceptions.ClientException, e:
|
||||
LOG.exception("ClientException in FloatingIpAllocate")
|
||||
messages.error(request, _('Unable to allocate Floating IP '
|
||||
'"%(ip)s" to tenant "%(tenant)s".')
|
||||
% {"ip": fip.ip, "tenant": tenant_id})
|
||||
return shortcuts.redirect('horizon:nova:access_and_security:index')
|
||||
|
||||
|
||||
|
@ -102,6 +91,9 @@ class FloatingIPsTable(tables.DataTable):
|
|||
instance = tables.Column("instance_id",
|
||||
verbose_name=_("Instance"),
|
||||
empty_value="-")
|
||||
pool = tables.Column("pool",
|
||||
verbose_name=_("Floating Ip Pool"),
|
||||
empty_value="-")
|
||||
|
||||
def sanitize_id(self, obj_id):
|
||||
return int(obj_id)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
from .views import AssociateView
|
||||
from .views import AssociateView, AllocateView
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^(?P<ip_id>[^/]+)/associate/$',
|
||||
AssociateView.as_view(),
|
||||
name='associate')
|
||||
name='associate'),
|
||||
url(r'^allocate/$',
|
||||
AllocateView.as_view(),
|
||||
name='allocate')
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
@ -28,7 +29,7 @@ from django.utils.translation import ugettext as _
|
|||
|
||||
from horizon import api
|
||||
from horizon import forms
|
||||
from .forms import FloatingIpAssociate
|
||||
from .forms import FloatingIpAssociate, FloatingIpAllocate
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -56,3 +57,19 @@ class AssociateView(forms.ModalFormView):
|
|||
return {'floating_ip_id': self.object.id,
|
||||
'floating_ip': self.object.ip,
|
||||
'instances': instances}
|
||||
|
||||
|
||||
class AllocateView(forms.ModalFormView):
|
||||
form_class = FloatingIpAllocate
|
||||
template_name = 'nova/access_and_security/floating_ips/allocate.html'
|
||||
context_object_name = 'floating_ip'
|
||||
|
||||
def get_initial(self):
|
||||
pools = api.floating_ip_pools_list(self.request)
|
||||
if pools:
|
||||
pool_list = [(pool.name, pool.name)
|
||||
for pool in api.floating_ip_pools_list(self.request)]
|
||||
else:
|
||||
pool_list = [(None, _("There are no Floating IP Pools"))]
|
||||
return {'tenant_id': self.request.user.tenant_id,
|
||||
'pool_list': pool_list}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}associate_floating_ip_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:nova:access_and_security:floating_ips:allocate %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Allocate Floating IP" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>{% trans "Allocate a floating IP from a given floating ip pool." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn primary pull-right" type="submit" value="{% trans "Allocate IP" %}" />
|
||||
<a href="{% url horizon:nova:access_and_security:index %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'nova/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Allocate Floating IP" %}{% endblock %}
|
||||
|
||||
{% block dash_main %}
|
||||
{% include 'nova/access_and_security/floating_ips/_allocate.html' %}
|
||||
{% endblock %}
|
|
@ -5,6 +5,7 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
|
@ -22,7 +23,7 @@ from __future__ import absolute_import
|
|||
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
from mox import IsA
|
||||
from mox import IsA, IgnoreArg
|
||||
from openstackx import admin as OSAdmin
|
||||
from openstackx import auth as OSAuth
|
||||
from openstackx import extras as OSExtras
|
||||
|
@ -477,17 +478,30 @@ class APIExtensionTests(APITestCase):
|
|||
|
||||
self.assertIsInstance(floating_ip, api.FloatingIp)
|
||||
|
||||
def test_tenant_floating_ip_allocate(self):
|
||||
def test_tenant_floating_ip_allocate_without_pool(self):
|
||||
novaclient = self.stub_novaclient()
|
||||
|
||||
novaclient.floating_ips = self.mox.CreateMockAnything()
|
||||
novaclient.floating_ips.create().AndReturn(self.floating_ip)
|
||||
novaclient.floating_ips.create(pool=IgnoreArg()).\
|
||||
AndReturn(self.floating_ip)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
floating_ip = api.tenant_floating_ip_allocate(self.request)
|
||||
|
||||
self.assertIsInstance(floating_ip, api.FloatingIp)
|
||||
|
||||
def test_tenant_floating_ip_allocate_with_pool(self):
|
||||
novaclient = self.stub_novaclient()
|
||||
|
||||
novaclient.floating_ips = self.mox.CreateMockAnything()
|
||||
novaclient.floating_ips.create(pool="nova").AndReturn(self.floating_ip)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
floating_ip = api.tenant_floating_ip_allocate(self.request,
|
||||
pool='nova')
|
||||
|
||||
self.assertIsInstance(floating_ip, api.FloatingIp)
|
||||
|
||||
def test_tenant_floating_ip_release(self):
|
||||
novaclient = self.stub_novaclient()
|
||||
|
||||
|
|
Loading…
Reference in New Issue