Port Forwardings tab

Change-Id: Iaf964a6c59ef1818e32202a9980df8e83bbbceed
This commit is contained in:
Eddie Ramirez 2018-08-08 12:28:12 -07:00
parent a814981a9f
commit 47a3e7f204
15 changed files with 576 additions and 1 deletions

1
.gitignore vendored
View File

@ -29,3 +29,4 @@ tags
ghostdriver.log
.testrepository
.idea
.vscode

View File

@ -4,9 +4,10 @@
# SPDX-License-Identifier: Apache-2.0
#
import six
from django.conf import settings
from horizon import exceptions
import six
from openstack_dashboard.api import base
def get_request_page_size(request, limit=None):
default_limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
@ -15,3 +16,9 @@ def get_request_page_size(request, limit=None):
except Exception:
default_page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
return request.session.get('horizon_pagesize', default_page_size)
def is_TiS_region(request):
if not base.is_service_enabled(request, 'platform'):
return False
return True

View File

@ -0,0 +1,33 @@
from openstack_dashboard.api import base
from openstack_dashboard.api.neutron import *
class PortForwardingRule(base.APIDictWrapper):
pass
def portforwarding_list(request, **params):
rules = (neutronclient(request).
list_portforwardings(**params).get('portforwardings'))
return [PortForwardingRule(r) for r in rules]
def portforwarding_get(request, portforwarding_id):
rule = (neutronclient(request).
show_portforwarding(portforwarding_id).get('portforwarding'))
return PortForwardingRule(rule)
def portforwarding_create(request, **kwargs):
body = {'portforwarding': kwargs}
rule = neutronclient(request).create_portforwarding(body=body)
return PortForwardingRule(rule)
def portforwarding_update(request, portforwarding_id, **kwargs):
body = {'portforwarding': kwargs}
rule = neutronclient(request).update_portforwarding(
portforwarding_id, body=body).get('portforwarding')
return PortForwardingRule(rule)
def portforwarding_delete(request, portforwarding_id):
return neutronclient(request).delete_portforwarding(portforwarding_id)

View File

@ -0,0 +1,176 @@
# Copyright (c) 2013-2015,2017 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
import netaddr
from django.core.urlresolvers import reverse
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from horizon.utils import memoized
from openstack_dashboard import api
LOG = logging.getLogger(__name__)
PROTOCOL_CHOICES = [("tcp", "TCP"),
("udp", "UDP"),
("udp-lite", "UDP-Lite"),
("sctp", "SCTP"),
("dccp", "DCCP")]
class AddPortForwardingRule(forms.SelfHandlingForm):
inside_addr = forms.ChoiceField(
label=_("IP Address"),
required=True,
initial="Select an IP address",
help_text=_("Specify a private IP address which will be the "
"destination of the forwarding rule "
"(e.g., 192.168.0.254)."))
inside_port = forms.IntegerField(
label=_("Private Port"), required=True, initial="",
min_value=1, max_value=65535,
help_text=_("Specify a private layer4 protocol port number"))
outside_port = forms.IntegerField(
label=_("Public Port"), required=True, initial="",
min_value=1, max_value=65535,
help_text=_("Specify a public layer4 protocol port number"))
protocol = forms.ChoiceField(
label=_("Protocol"), required=True, initial="Select a protocol")
description = forms.CharField(label=_("Description"), required=False)
router_name = forms.CharField(label=_("Router Name"),
widget=forms.TextInput(
attrs={'readonly': 'readonly'}))
router_id = forms.CharField(label=_("Router ID"),
widget=forms.TextInput(
attrs={'readonly': 'readonly'}))
failure_url = 'horizon:project:routers:detail'
def __init__(self, request, *args, **kwargs):
super(AddPortForwardingRule, self).__init__(request, *args, **kwargs)
self.router_id = kwargs['initial']['router_id']
self.tenant_id = kwargs['initial']['tenant_id']
address_choices = self.populate_inside_addr_choices(request)
self.fields['inside_addr'].choices = address_choices
self.fields['protocol'].choices = PROTOCOL_CHOICES
@memoized.memoized_method
def _get_connected_ipv4_networks(self, request, router_id):
networks = set()
subnets = set()
ports = api.neutron.port_list(request, device_id=router_id)
for p in ports:
if p.device_owner not in api.neutron.ROUTER_INTERFACE_OWNERS:
continue
if not p.fixed_ips:
continue
networks.add(p.network_id)
for ip in p.fixed_ips:
if netaddr.valid_ipv4(ip['ip_address']):
subnets.add(ip['subnet_id'])
return (list(networks), list(subnets))
@memoized.memoized_method
def _get_available_addresses(self, request, network_ids, subnet_ids):
address_list = []
for network_id in network_ids:
ports = api.neutron.port_list(request, network_id=network_id)
for p in ports:
if p.device_owner.startswith('network:'):
continue
for ip in p.fixed_ips:
if ip['subnet_id'] in subnet_ids:
record = (ip['ip_address'], p.id, p.device_id)
address_list.append(record)
return address_list
@memoized.memoized_method
def _get_servers(self, request):
search_opts = {'project_id': self.tenant_id}
servers, has_more = api.nova.server_list(
self.request, search_opts=search_opts)
server_dict = SortedDict([(s.id, s.name) for s in servers])
return server_dict
def populate_inside_addr_choices(self, request):
network_ids, subnet_ids = self._get_connected_ipv4_networks(
request, self.router_id)
addresses = self._get_available_addresses(
request, network_ids, subnet_ids)
servers = self._get_servers(request)
choices = []
for ip_address, port_id, device_id in addresses:
server = servers.get(device_id)
display_name = ip_address
if server:
display_name += " : {}".format(server)
choices.append((ip_address, display_name))
choices.insert(0, ("", "Select an IP address"))
return choices
def handle(self, request, data):
try:
router_id = data['router_id']
params = {'router_id': data['router_id'],
'inside_addr': data['inside_addr'],
'inside_port': data['inside_port'],
'outside_port': data['outside_port'],
'protocol': data['protocol'].lower()}
if 'description' in data:
params['description'] = data['description']
api.neutron.portforwarding_create(request, **params)
except Exception as e:
self._handle_error(request, router_id, e)
msg = _('Port forwarding rule added')
LOG.debug(msg)
messages.success(request, msg)
return True
def _handle_error(self, request, router_id, reason):
msg = _('Failed to add port forwarding rule: %s') % reason
LOG.info(msg)
redirect = reverse(self.failure_url, args=[router_id])
exceptions.handle(request, msg, redirect=redirect)
class UpdatePortForwardingRule(AddPortForwardingRule):
portforwarding_id = forms.CharField(
label=_("ID"), required=False,
widget=forms.TextInput(attrs={'readonly': 'readonly'}))
def __init__(self, request, *args, **kwargs):
super(UpdatePortForwardingRule, self).__init__(
request, *args, **kwargs)
def handle(self, request, data):
try:
portforwarding_id = data['portforwarding_id']
router_id = data['router_id']
params = {'inside_addr': data['inside_addr'],
'inside_port': data['inside_port'],
'outside_port': data['outside_port'],
'protocol': data['protocol'].lower()}
if 'description' in data:
params['description'] = data['description']
api.neutron.portforwarding_update(request,
portforwarding_id,
**params)
except Exception as e:
self._handle_error(request, router_id, e)
msg = _('Port forwarding rule updated')
LOG.debug(msg)
messages.success(request, msg)
return True
def _handle_error(self, request, router_id, reason):
msg = _('Failed to update port forwarding rule: %s') % reason
LOG.info(msg)
redirect = reverse(self.failure_url, args=[router_id])
exceptions.handle(request, msg, redirect=redirect)

View File

@ -0,0 +1,110 @@
# Copyright (c) 2013-2015 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from horizon import exceptions
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard import policy
LOG = logging.getLogger(__name__)
class AddPortForwardingRule(policy.PolicyTargetMixin, tables.LinkAction):
name = "createportforwardingrule"
verbose_name = _("Add Rule")
url = "horizon:project:routers:addportforwardingrule"
classes = ("ajax-modal",)
icon = "plus"
policy_rules = (("network", "create_portforwarding"),)
def get_link_url(self, datum=None):
router_id = self.table.kwargs['router_id']
return reverse(self.url, args=(router_id,))
class UpdatePortForwardingRule(policy.PolicyTargetMixin, tables.LinkAction):
name = "updateportforwardingrule"
verbose_name = _("Update Rule")
url = "horizon:project:routers:updateportforwardingrule"
classes = ("ajax-modal",)
icon = "plus"
policy_rules = (("network", "update_portforwarding"),)
def get_link_url(self, datum=None):
router_id = self.table.kwargs['router_id']
portforwarding_id = datum['id']
return reverse(self.url, args=(router_id, portforwarding_id,))
class RemovePortForwardingRule(policy.PolicyTargetMixin, tables.DeleteAction):
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Delete Rule",
u"Delete Rule",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Deleted Port Forwarding Rule",
u"Deleted Port Forwarding Rules",
count
)
failure_url = 'horizon:project:routers:detail'
policy_rules = (("network", "delete_portforwarding"),)
def delete(self, request, obj_id):
try:
api.neutron.portforwarding_delete(
request, portforwarding_id=obj_id)
except Exception:
msg = _('Failed to delete port forwarding rule %s') % obj_id
LOG.info(msg)
router_id = self.table.kwargs['router_id']
redirect = reverse(self.failure_url,
args=[router_id])
exceptions.handle(request, msg, redirect=redirect)
def _get_port_link_url(rule):
port = rule['port']
link = 'horizon:project:networks:ports:detail'
return reverse(link, args=(port.id,))
def _get_port_name_or_id(rule):
port = rule['port']
if port.name:
return port.name
return '(' + port.id[:8] + ')'
class PortForwardingRulesTable(tables.DataTable):
port = tables.Column(_get_port_name_or_id, verbose_name=_("Port"),
link=_get_port_link_url)
inside_addr = tables.Column("inside_addr",
verbose_name=_("Private Address"))
inside_port = tables.Column("inside_port", verbose_name=_("Private Port"))
outside_port = tables.Column("outside_port", verbose_name=_("Public Port"))
protocol = tables.Column("protocol", verbose_name=_("Protocol"))
description = tables.Column("description", verbose_name=_("Description"))
def get_object_display(self, portforwarding):
return portforwarding.id
class Meta(object):
name = "portforwardings"
verbose_name = _("Port Forwarding Rules")
table_actions = (AddPortForwardingRule, RemovePortForwardingRule)
row_actions = (UpdatePortForwardingRule, RemovePortForwardingRule, )

View File

@ -0,0 +1,34 @@
# Copyright (c) 2013-2015 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tabs
from starlingx_dashboard import api as stx_api
class OverviewTab(tabs.Tab):
name = _("Overview")
slug = "overview"
template_name = "project/networks/portforwardings/_detail_overview.html"
failure_url = 'horizon:project:routers:index'
def get_context_data(self, request):
portforwarding_id = self.tab_group.kwargs['portforwarding_id']
try:
rule = stx_api.neutron.portforwarding_get(self.request,
portforwarding_id)
except Exception:
redirect = reverse(self.failure_url)
msg = _('Unable to retrieve port forwarding details.')
exceptions.handle(request, msg, redirect=redirect)
return {'portforwarding': rule}
class PortForwardingDetailTabs(tabs.TabGroup):
slug = "portforwarding_details"
tabs = (OverviewTab,)

View File

@ -0,0 +1,16 @@
# Copyright (c) 2013-2015 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.conf.urls import patterns
from django.conf.urls import url
from openstack_dashboard.dashboards.project.routers.portforwardings \
import views
PORTFORWARDINGS = r'^(?P<portforwarding_id>[^/]+)/%s$'
urlpatterns = patterns(
'horizon.dashboards.project.networks.portforwardings.views',
url(PORTFORWARDINGS % 'detail', views.DetailView.as_view(), name='detail'))

View File

@ -0,0 +1,112 @@
# Copyright (c) 2013-2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import tabs
from horizon.utils import memoized
from openstack_dashboard import api
from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.project.routers.portforwardings \
import forms as project_forms
from starlingx_dashboard.dashboards.project.routers.portforwardings \
import tabs as project_tabs
class AddPortForwardingRuleView(forms.ModalFormView):
form_class = project_forms.AddPortForwardingRule
template_name = 'project/routers/portforwardings/create.html'
success_url = 'horizon:project:routers:detail'
failure_url = 'horizon:project:routers:detail'
page_title = _("Add Port Forwarding Rule")
def get_success_url(self):
return reverse(self.success_url,
args=(self.kwargs['router_id'],))
@memoized.memoized_method
def get_router_object(self):
try:
router_id = self.kwargs["router_id"]
return api.neutron.router_get(self.request, router_id)
except Exception:
redirect = reverse(self.failure_url, args=[router_id])
msg = _("Unable to retrieve router.")
exceptions.handle(self.request, msg, redirect=redirect)
def get_context_data(self, **kwargs):
context = (super(AddPortForwardingRuleView, self).
get_context_data(**kwargs))
context['router'] = self.get_router_object()
return context
def get_initial(self):
router = self.get_router_object()
return {"router_id": self.kwargs['router_id'],
"router_name": router.name,
"tenant_id": router.tenant_id}
class UpdatePortForwardingRuleView(forms.ModalFormView):
form_class = project_forms.UpdatePortForwardingRule
template_name = 'project/routers/portforwardings/update.html'
success_url = 'horizon:project:routers:detail'
failure_url = 'horizon:project:routers:detail'
page_title = _("Update Port Forwarding Rule")
def get_success_url(self):
return reverse(self.success_url,
args=(self.kwargs['router_id'],))
@memoized.memoized_method
def get_router_object(self):
try:
router_id = self.kwargs["router_id"]
return api.neutron.router_get(self.request, router_id)
except Exception:
redirect = reverse(self.failure_url, args=[router_id])
msg = _("Unable to retrieve router.")
exceptions.handle(self.request, msg, redirect=redirect)
@memoized.memoized_method
def get_portforwarding_object(self):
try:
router_id = self.kwargs["router_id"]
portforwarding_id = self.kwargs["portforwarding_id"]
return stx_api.neutron.portforwarding_get(self.request,
portforwarding_id)
except Exception:
redirect = reverse(self.failure_url, args=[router_id])
msg = _("Unable to retrieve port forwarding rule.")
exceptions.handle(self.request, msg, redirect=redirect)
def get_context_data(self, **kwargs):
context = super(UpdatePortForwardingRuleView, self).get_context_data(
**kwargs)
context['router'] = self.get_router_object()
context['portforwarding'] = self.get_portforwarding_object()
return context
def get_initial(self):
router = self.get_router_object()
rule = self.get_portforwarding_object()
return {"router_id": self.kwargs['router_id'],
"router_name": router.name,
"tenant_id": router.tenant_id,
"portforwarding_id": self.kwargs['portforwarding_id'],
"inside_addr": rule.inside_addr,
"inside_port": rule.inside_port,
"outside_port": rule.outside_port,
"protocol": rule.protocol,
"description": rule.description}
class DetailView(tabs.TabView):
tab_group_class = project_tabs.PortForwardingDetailTabs
template_name = 'project/networks/portforwardings/detail.html'

View File

@ -0,0 +1,18 @@
from horizon import tabs
from starlingx_dashboard.api import base as stx_base
from starlingx_dashboard.dashboards.project.routers.portforwardings\
import tables
class PortForwardingTab(tabs.TableTab):
table_classes = (tables.PortForwardingRulesTable,)
name = _("Port Forwarding")
slug = "portforwardings"
template_name = "horizon/common/_detail_table.html"
def get_portforwardings_data(self):
return self.tab_group.kwargs['portforwardings']
def allowed(self, request):
return stx_base.base.is_TiS_region(request)

View File

@ -0,0 +1,27 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block form_id %}add_portforwarding_rule_form{% endblock %}
{% block form_action %}{% url 'horizon:project:routers:addportforwardingrule' router.id %}
{% endblock %}
{% block modal-header %}{% trans "Add Port Forwarding Rule" %}{% 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 "You can create a port forwarding rule from a public port to a private address and port." %}
</p>
</div>
{% endblock %}
{% block modal-footer %}
<a class="btn btn-default cancel" data-dismiss="modal">{% trans "Cancel" %}</a>
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Add Rule" %}"/>
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block form_id %}update_portforwarding_rule_form{% endblock %}
{% block form_action %}{% url 'horizon:project:routers:updateportforwardingrule' router.id portforwarding.id %}
{% endblock %}
{% block modal-header %}{% trans "Update Port Forwarding Rule" %}{% 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 "You can update the port forwarding rule details." %}
</p>
</div>
{% endblock %}
{% block modal-footer %}
<a class="btn btn-default cancel" data-dismiss="modal">{% trans "Cancel" %}</a>
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Update Rule" %}"/>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Add Port Forwarding Rule" %}{% endblock %}
{% block main %}
{% include "project/routers/portforwardings/_create.html" %}
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Update Port Forwarding Rule" %}{% endblock %}
{% block main %}
{% include "project/routers/portforwardings/_update.html" %}
{% endblock %}