diff --git a/gbpui/client.py b/gbpui/client.py
index 5ac1678..c9979e4 100644
--- a/gbpui/client.py
+++ b/gbpui/client.py
@@ -78,6 +78,16 @@ class ExternalConnectivity(neutron.NeutronAPIDictWrapper):
return ec_dict
+class NATPool(neutron.NeutronAPIDictWrapper):
+
+ """Wrapper for neutron nat pool."""
+
+ def get_dict(self):
+ natpool_dict = self._apidict
+ natpool_dict['natpool_id'] = natpool_dict['id']
+ return natpool_dict
+
+
class Contract(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron policy_rule_set."""
@@ -418,6 +428,38 @@ def externalconnectivity_list(request, tenant_id, **kwargs):
for external_connectivity in external_connectivities]
+def natpool_list(request, tenant_id, **kwargs):
+ nat_pools = gbpclient(request).list_nat_pools(
+ tenant_id=tenant_id, shared=False, **kwargs).get('nat_pools')
+ nat_pools.extend(gbpclient(request).list_nat_pools(
+ shared=True, **kwargs).get('nat_pools'))
+ return [NATPool(nat_pool) for nat_pool in nat_pools]
+
+
+def create_natpool(request, **kwargs):
+ body = {'nat_pool': kwargs}
+ np = gbpclient(request).create_nat_pool(
+ body).get('nat_pool')
+ return NATPool(np)
+
+
+def get_natpool(request, nat_pool_id):
+ np = gbpclient(request).show_nat_pool(
+ nat_pool_id).get('nat_pool')
+ return NATPool(np)
+
+
+def delete_natpool(request, nat_pool_id, **kwargs):
+ gbpclient(request).delete_nat_pool(nat_pool_id)
+
+
+def update_natpool(request, nat_pool_id, **kwargs):
+ body = {'nat_pool': kwargs}
+ np = gbpclient(request).update_nat_pool(
+ nat_pool_id, body).get('nat_pool')
+ return NATPool(np)
+
+
def create_externalconnectivity(request, **kwargs):
body = {'external_segment': kwargs}
es = gbpclient(request).create_external_segment(
diff --git a/gbpui/column_filters.py b/gbpui/column_filters.py
index 4d3758b..9939167 100644
--- a/gbpui/column_filters.py
+++ b/gbpui/column_filters.py
@@ -268,3 +268,20 @@ def update_l3_policy_attributes(request, l3_policy):
tag = '-'
setattr(l3_policy, 'external_segments', tag)
return l3_policy
+
+
+def update_nat_pool_attributes(request, nat_pool):
+ url = "horizon:project:network_policy:external_connectivity_details"
+ id = nat_pool.external_segment_id
+ value = ["
"]
+ li = \
+ lambda x: "- " + x.name + "" + "
"
+ external_connectivity = client.get_externalconnectivity(request,
+ id)
+ value.append(li(external_connectivity))
+ value.append("
")
+ tag = mark_safe("".join(value))
+ setattr(nat_pool, 'external_segment_id', tag)
+ return nat_pool
diff --git a/gbpui/panels/network_policy/forms.py b/gbpui/panels/network_policy/forms.py
index 390d4a3..ce87e73 100644
--- a/gbpui/panels/network_policy/forms.py
+++ b/gbpui/panels/network_policy/forms.py
@@ -394,6 +394,112 @@ class UpdateServicePolicyForm(BaseUpdateForm):
exceptions.handle(request, msg, redirect=shortcuts.redirect)
+class CreateNATPoolForm(forms.SelfHandlingForm):
+ name = forms.CharField(max_length=80, label=_("Name"))
+ description = forms.CharField(
+ max_length=80, label=_("Description"), required=False)
+ ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
+ widget=forms.Select(attrs={
+ 'class': 'switchable',
+ 'data-slug': 'ipversion',
+ }),
+ label=_("IP Version"))
+ ip_pool = forms.IPField(label=_("CIDR"),
+ initial="", required=True,
+ help_text=_("Network address in CIDR format "
+ "(e.g. 192.168.0.0/24,"
+ "2001:DB8::/48)"),
+ version=forms.IPv4 | forms.IPv6, mask=True)
+ external_segment_id = forms.ChoiceField(label=_("External Segment"),
+ required=True)
+ shared = forms.BooleanField(label=_("Shared"),
+ initial=False, required=False)
+
+ def __init__(self, request, *args, **kwargs):
+ super(CreateNATPoolForm, self).__init__(request,
+ *args,
+ **kwargs)
+ ec_list = client.externalconnectivity_list(request,
+ tenant_id=request.user.tenant_id)
+ external_segments_options = [(ec.id, ec.name) for ec in ec_list]
+ self.fields['external_segment_id'].choices = external_segments_options
+
+ def handle(self, request, context):
+ url = reverse("horizon:project:network_policy:index")
+ try:
+ if context.get('name'):
+ context['name'] = html.escape(context['name'])
+ if context.get('description'):
+ context['description'] = html.escape(context['description'])
+ client.create_natpool(request, **context)
+ msg = _("NAT Pool created successfully!")
+ LOG.debug(msg)
+ messages.success(request, msg)
+ return http.HttpResponseRedirect(url)
+ except Exception as e:
+ msg = _("Failed to NAT Pool. %s") % (str(e))
+ LOG.error(msg)
+ exceptions.handle(request, msg, redirect=url)
+
+
+class UpdateNATPoolForm(BaseUpdateForm):
+ name = forms.CharField(max_length=80, label=_("Name"))
+ description = forms.CharField(
+ max_length=80, label=_("Description"), required=False)
+ ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
+ widget=forms.Select(attrs={
+ 'class': 'switchable',
+ 'data-slug': 'ipversion',
+ }),
+ label=_("IP Version"))
+ ip_pool = forms.IPField(label=_("CIDR"),
+ initial="", required=True,
+ help_text=_("Network address in CIDR format "
+ "(e.g. 192.168.0.0/24,"
+ "2001:DB8::/48)"),
+ version=forms.IPv4 | forms.IPv6, mask=True)
+ external_segment_id = forms.ChoiceField(label=_("External Segment"),
+ required=True)
+ shared = forms.BooleanField(label=_("Shared"),
+ initial=False, required=False)
+
+ def __init__(self, request, *args, **kwargs):
+ super(UpdateNATPoolForm, self).__init__(request,
+ *args,
+ **kwargs)
+ nat_pool_id = self.initial['nat_pool_id']
+ ec_list = client.externalconnectivity_list(request,
+ tenant_id=request.user.tenant_id)
+ external_segments_options = [(ec.id, ec.name) for ec in ec_list]
+ self.fields['external_segment_id'].choices = external_segments_options
+ nat_pool = client.get_natpool(request, nat_pool_id)
+ attributes = ['name', 'description',
+ 'ip_version', 'ip_pool', 'external_segment_id']
+ for attr in attributes:
+ self.fields[attr].initial = str(nat_pool[attr])
+ self.fields['shared'].initial = nat_pool['shared']
+
+ def handle(self, request, context):
+ url = reverse("horizon:project:network_policy:index")
+ try:
+ if context.get('name'):
+ context['name'] = html.escape(context['name'])
+ if context.get('description'):
+ context['description'] = html.escape(context['description'])
+ nat_pool_id = self.initial['nat_pool_id']
+ client.update_natpool(
+ request, nat_pool_id, **context)
+ msg = _("NAT Pool updated successfully!")
+ LOG.debug(msg)
+ messages.success(request, msg)
+ return http.HttpResponseRedirect(url)
+ except Exception as e:
+ msg = _("Failed to update NAT Pool.%s") % \
+ (str(e))
+ LOG.error(msg)
+ exceptions.handle(request, msg, redirect=url)
+
+
class UpdateExternalConnectivityForm(forms.SelfHandlingForm):
name = forms.CharField(max_length=80, label=_("Name"))
description = forms.CharField(
diff --git a/gbpui/panels/network_policy/tables.py b/gbpui/panels/network_policy/tables.py
index 969c430..15325f9 100644
--- a/gbpui/panels/network_policy/tables.py
+++ b/gbpui/panels/network_policy/tables.py
@@ -186,3 +186,47 @@ class ExternalConnectivityTable(tables.DataTable):
DeleteExternalConnectivityLink,)
row_actions = (EditExternalConnectivityLink,
DeleteExternalConnectivityLink,)
+
+
+class CreateNATPoolLink(tables.LinkAction):
+ name = "create_nat_pool"
+ verbose_name = _("Create NAT Pool")
+ url = "horizon:project:network_policy:create_nat_pool"
+ classes = ("ajax-modal", "btn-addnatpool")
+
+
+class DeleteNATPoolLink(tables.DeleteAction):
+ name = "deletenatpool"
+ action_present = _("Delete")
+ action_past = _("Scheduled deletion of %(data_type)s")
+ data_type_singular = _("NAT Pool")
+ data_type_plural = _("NAT Pools")
+
+
+class EditNATPoolLink(tables.LinkAction):
+ name = "update_nat_pool"
+ verbose_name = _("Edit")
+ classes = ("ajax-modal", "btn-update",)
+
+ def get_link_url(self, nat_pool):
+ urlstring = \
+ "horizon:project:network_policy:update_natpool"
+ base_url = reverse(urlstring,
+ kwargs={'nat_pool_id': nat_pool.id})
+ return base_url
+
+
+class NATPoolTable(tables.DataTable):
+ name = tables.Column("name", verbose_name=_("Name"),
+ link="horizon:project:network_policy:nat_pool_details")
+ description = tables.Column("description", verbose_name=_("Description"))
+ ip_version = tables.Column("ip_version", verbose_name=_("IP Version"))
+ cidr = tables.Column("ip_pool", verbose_name=_("IP Pool"))
+ external_segment = tables.Column("external_segment_id",
+ verbose_name=_("External Segment"))
+
+ class Meta(object):
+ name = "nat_pool_table"
+ verbose_name = _("NAT Pool")
+ table_actions = (CreateNATPoolLink, DeleteNATPoolLink,)
+ row_actions = (EditNATPoolLink, DeleteNATPoolLink,)
diff --git a/gbpui/panels/network_policy/tabs.py b/gbpui/panels/network_policy/tabs.py
index 3db81d7..57c97e0 100644
--- a/gbpui/panels/network_policy/tabs.py
+++ b/gbpui/panels/network_policy/tabs.py
@@ -152,6 +152,47 @@ class ExternalConnectivityDetailsTab(tabs.Tab):
return {'external_connectivity': external_connectivity}
+class NATPoolTab(tabs.TableTab):
+ table_classes = (tables.NATPoolTable,)
+ name = _("NAT Pool")
+ slug = "nat_pool"
+ template_name = "horizon/common/_detail_table.html"
+
+ def get_nat_pool_table_data(self):
+ nat_pool_list = []
+ try:
+ nat_pools = \
+ client.natpool_list(self.request,
+ self.request.user.tenant_id)
+ update = lambda x: gfilters.update_nat_pool_attributes(
+ self.request, x)
+ nat_pool_list = [update(nat_pool) for nat_pool in nat_pools]
+ except Exception:
+ exceptions.handle(self.tab_group.request,
+ _('Unable to retrieve nat pool list.'))
+ return nat_pool_list
+
+
+class NATPoolDetailsTab(tabs.Tab):
+ name = _("NAT Pool Details")
+ slug = "nat_pool_details"
+ template_name = \
+ "project/network_policy/_nat_pool_details.html"
+ failure_url = reverse_lazy('horizon:project:network_policy:index')
+
+ def get_context_data(self, request):
+ nat_pool_id = \
+ self.tab_group.kwargs['nat_pool_id']
+ try:
+ nat_pool = client.get_natpool(request,
+ nat_pool_id)
+ except Exception:
+ exceptions.handle(
+ request, _('Unable to retrieve nat pool details.'),
+ redirect=self.failure_url)
+ return {'nat_pool': nat_pool}
+
+
class ServicePolicyDetailsTabs(tabs.TabGroup):
slug = "service_policy_details_tab"
tabs = (ServicePolicyDetailsTab,)
@@ -164,9 +205,15 @@ class ExternalConnectivityDetailsTabs(tabs.TabGroup):
sticky = True
+class NATPoolDetailsTabs(tabs.TabGroup):
+ slug = "nat_pool_details_tab"
+ tabs = (NATPoolDetailsTab,)
+ sticky = True
+
+
class L3PolicyTabs(tabs.TabGroup):
slug = "l3policy_tab"
- tabs = (L3PolicyTab, ServicePolicyTab, ExternalConnectivityTab,)
+ tabs = (L3PolicyTab, ServicePolicyTab, ExternalConnectivityTab, NATPoolTab)
sticky = True
diff --git a/gbpui/panels/network_policy/templates/network_policy/_create_nat_pool.html b/gbpui/panels/network_policy/templates/network_policy/_create_nat_pool.html
new file mode 100644
index 0000000..3087b2b
--- /dev/null
+++ b/gbpui/panels/network_policy/templates/network_policy/_create_nat_pool.html
@@ -0,0 +1,24 @@
+{% extends "horizon/common/_modal_form.html" %}
+{% load i18n %}
+{% load url from future %}
+
+{% block form_id %}create_nat_pool{% endblock %}
+{% block form_action %}{% url 'horizon:project:network_policy:create_nat_pool' %}{% endblock %}
+
+{% block modal-header %}{% trans "Create NAT Pool" %}{% endblock %}
+
+{% block modal-body %}
+
+
+
+
+
{% trans "Description:" %}
+
+{% endblock %}
+
+{% block modal-footer %}
+
+ {% trans "Cancel" %}
+{% endblock %}
diff --git a/gbpui/panels/network_policy/templates/network_policy/_nat_pool_details.html b/gbpui/panels/network_policy/templates/network_policy/_nat_pool_details.html
new file mode 100644
index 0000000..300e0f0
--- /dev/null
+++ b/gbpui/panels/network_policy/templates/network_policy/_nat_pool_details.html
@@ -0,0 +1,28 @@
+{% load i18n sizeformat parse_date %}
+{% load url from future %}
+
+
+
+
+ - {% trans "Name" %}
+ - {{ nat_pool.name|default:_("-") }}
+
+ - {% trans "Description" %}
+ - {{ nat_pool.description|default:_("-") }}
+
+ - {% trans "ID" %}
+ - {{ nat_pool.id }}
+
+ - {% trans "IP Version" %}
+ - {{ nat_pool.ip_version }}
+
+ - {% trans "IP Pool" %}
+ - {{ nat_pool.ip_pool }}
+
+ - {% trans "External Segment ID" %}
+ - {{ nat_pool.external_segment_id }}
+
+ - {% trans "Shared" %}
+ - {{ nat_pool.shared }}
+
+
diff --git a/gbpui/panels/network_policy/templates/network_policy/_update_nat_pool.html b/gbpui/panels/network_policy/templates/network_policy/_update_nat_pool.html
new file mode 100644
index 0000000..d803ce6
--- /dev/null
+++ b/gbpui/panels/network_policy/templates/network_policy/_update_nat_pool.html
@@ -0,0 +1,25 @@
+{% extends "horizon/common/_modal_form.html" %}
+{% load i18n %}
+{% load url from future %}
+
+{% block form_id %}update_nat_pool_form{% endblock %}
+{% block form_action %}{% url 'horizon:project:network_policy:update_natpool' nat_pool_id %}{% endblock %}
+
+{% block modal-header %}{% trans "Update NAT Pool" %}{% endblock %}
+
+{% block modal-body %}
+
+
+
+
+
{% trans "Description:" %}
+
{% trans "Update NAT Pool." %}
+
+{% endblock %}
+
+{% block modal-footer %}
+
+ {% trans "Cancel" %}
+{% endblock %}
diff --git a/gbpui/panels/network_policy/urls.py b/gbpui/panels/network_policy/urls.py
index b35f38e..ad91b58 100644
--- a/gbpui/panels/network_policy/urls.py
+++ b/gbpui/panels/network_policy/urls.py
@@ -36,6 +36,9 @@ urlpatterns = patterns('',
url(r'^createexternalconnectivity$',
views.CreateExternalConnectivityView.as_view(),
name='create_external_connectivity'),
+ url(r'^createnatpool$',
+ views.CreateNATPoolView.as_view(),
+ name='create_nat_pool'),
url(r'^update_servicepolicy/(?P[^/]+)/$',
views.UpdateServicePolicyView.as_view(),
name='update_service_policy'),
@@ -43,6 +46,14 @@ urlpatterns = patterns('',
'(?P[^/]+)/$',
views.UpdateExternalConnectivityView.as_view(),
name='update_externalconnectivity'),
+ url(r'^update_natpool/'
+ '(?P[^/]+)/$',
+ views.UpdateNATPoolView.as_view(),
+ name='update_natpool'),
+ url(r'^natpool/'
+ '(?P[^/]+)/$',
+ views.NATPoolDetailsView.as_view(),
+ name='nat_pool_details'),
url(r'^servicepolicy/(?P[^/]+)/$',
views.ServicePolicyDetailsView.as_view(),
name='service_policy_details'),
diff --git a/gbpui/panels/network_policy/views.py b/gbpui/panels/network_policy/views.py
index 744dec2..f10908c 100644
--- a/gbpui/panels/network_policy/views.py
+++ b/gbpui/panels/network_policy/views.py
@@ -65,6 +65,15 @@ class IndexView(tabs.TabView):
except Exception as e:
msg = _('Unable to delete action. %s') % (str(e))
exceptions.handle(request, msg)
+ if obj_type == 'natpool':
+ for obj_id in obj_ids:
+ try:
+ client.delete_natpool(request, obj_id)
+ messages.success(request,
+ _('Deleted NAT Pool %s') % obj_id)
+ except Exception as e:
+ msg = _('Unable to delete action. %s') % (str(e))
+ exceptions.handle(request, msg)
return self.get(request, *args, **kwargs)
@@ -196,6 +205,20 @@ class AddExternalRouteParamView(forms.ModalFormView):
return params.name
+class UpdateNATPoolView(forms.ModalFormView):
+ form_class = np_forms.UpdateNATPoolForm
+ template_name = "project/network_policy/update_nat_pool.html"
+
+ def get_context_data(self, **kwargs):
+ context = super(
+ UpdateNATPoolView, self).get_context_data(**kwargs)
+ context['nat_pool_id'] = self.kwargs['nat_pool_id']
+ return context
+
+ def get_initial(self):
+ return self.kwargs
+
+
class UpdateExternalConnectivityView(forms.ModalFormView):
form_class = np_forms.UpdateExternalConnectivityForm
template_name = "project/network_policy/update_external_connectivity.html"
@@ -249,3 +272,18 @@ class CreateExternalConnectivityView(forms.ModalFormView):
class ExternalConnectivityDetailsView(tabs.TabView):
tab_group_class = (np_tabs.ExternalConnectivityDetailsTabs)
template_name = 'project/network_policy/details_tabs.html'
+
+
+class CreateNATPoolView(forms.ModalFormView):
+ form_class = np_forms.CreateNATPoolForm
+ template_name = "project/network_policy/create_nat_pool.html"
+
+ def get_context_data(self, **kwargs):
+ context = super(
+ CreateNATPoolView, self).get_context_data(**kwargs)
+ return context
+
+
+class NATPoolDetailsView(tabs.TabView):
+ tab_group_class = (np_tabs.NATPoolDetailsTabs)
+ template_name = 'project/network_policy/details_tabs.html'