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 = ["") + 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 %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% 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 %} +
+
+ {% include "horizon/common/_form_fields.html" %} +
+
+
+

{% 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'