From 2807aa6bdc782f50140dcb25ddc9695a7eebb8e0 Mon Sep 17 00:00:00 2001 From: Aditya Vaja Date: Wed, 27 Jul 2016 15:25:02 -0700 Subject: [PATCH] Remove router rules extension Router rules is a horizon extension provided by Big Switch Networks. As part of the horizon-vendor-split work, we drop the extension from upstream horizon. It is now available as a separate plugin at https://github.com/bigswitch/horizon-bsn Change-Id: I439f6f87057547f9bc0fbb7089d37b4e9603b1c1 Partially-implements: blueprint horizon-vendor-split --- .../dashboards/admin/routers/tabs.py | 5 +- .../extensions/routerrules/__init__.py | 0 .../routers/extensions/routerrules/forms.py | 97 -------- .../extensions/routerrules/rulemanager.py | 103 -------- .../routers/extensions/routerrules/tables.py | 79 ------ .../routers/extensions/routerrules/tabs.py | 227 ------------------ .../routers/extensions/routerrules/views.py | 59 ----- .../dashboards/project/routers/tabs.py | 5 +- .../extensions/routerrules/_create.html | 23 -- .../extensions/routerrules/create.html | 7 - .../routers/extensions/routerrules/grid.html | 156 ------------ .../dashboards/project/routers/tests.py | 146 ----------- .../dashboards/project/routers/urls.py | 5 - ...horizon-vendor-split-4451bc1988485957.yaml | 6 + 14 files changed, 8 insertions(+), 910 deletions(-) delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/__init__.py delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/forms.py delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/rulemanager.py delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/tables.py delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py delete mode 100644 openstack_dashboard/dashboards/project/routers/extensions/routerrules/views.py delete mode 100644 openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/_create.html delete mode 100644 openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/create.html delete mode 100644 openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/grid.html create mode 100644 releasenotes/notes/bp-horizon-vendor-split-4451bc1988485957.yaml diff --git a/openstack_dashboard/dashboards/admin/routers/tabs.py b/openstack_dashboard/dashboards/admin/routers/tabs.py index 2a94bcf06..49e922868 100644 --- a/openstack_dashboard/dashboards/admin/routers/tabs.py +++ b/openstack_dashboard/dashboards/admin/routers/tabs.py @@ -17,8 +17,6 @@ from openstack_dashboard.dashboards.admin.routers.extensions.extraroutes\ from openstack_dashboard.dashboards.admin.routers.ports import tables as ptbl from openstack_dashboard.dashboards.project.routers.extensions.extraroutes\ import tabs as er_tabs -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import tabs as rr_tabs from openstack_dashboard.dashboards.project.routers import tabs as r_tabs @@ -35,6 +33,5 @@ class InterfacesTab(r_tabs.InterfacesTab): class RouterDetailTabs(r_tabs.RouterDetailTabs): - tabs = (OverviewTab, InterfacesTab, ExtraRoutesTab, rr_tabs.RulesGridTab, - rr_tabs.RouterRulesTab) + tabs = (OverviewTab, InterfacesTab, ExtraRoutesTab) sticky = True diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/__init__.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/forms.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/forms.py deleted file mode 100644 index e43a68a6b..000000000 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/forms.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2013, Big Switch Networks -# -# 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from django.core.exceptions import ValidationError # noqa -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 messages -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import rulemanager - -LOG = logging.getLogger(__name__) - - -class RuleCIDRField(forms.IPField): - """Extends IPField to allow ('any','external') keywords and requires CIDR - """ - def __init__(self, *args, **kwargs): - kwargs['mask'] = True - super(RuleCIDRField, self).__init__(*args, **kwargs) - - def validate(self, value): - keywords = ['any', 'external'] - if value in keywords: - self.ip = value - else: - if '/' not in value: - raise ValidationError(_("Input must be in CIDR format")) - super(RuleCIDRField, self).validate(value) - - -class AddRouterRule(forms.SelfHandlingForm): - source = RuleCIDRField(label=_("Source CIDR"), - widget=forms.TextInput()) - destination = RuleCIDRField(label=_("Destination CIDR"), - widget=forms.TextInput()) - action = forms.ChoiceField(label=_("Action")) - nexthops = forms.MultiIPField(label=_("Optional: Next Hop " - "Addresses (comma delimited)"), - widget=forms.TextInput(), required=False) - 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(AddRouterRule, self).__init__(request, *args, **kwargs) - self.fields['action'].choices = [('permit', _('Permit')), - ('deny', _('Deny'))] - - def handle(self, request, data, **kwargs): - try: - if 'rule_to_delete' in request.POST: - rulemanager.remove_rules(request, - [request.POST['rule_to_delete']], - router_id=data['router_id']) - except Exception: - exceptions.handle(request, _('Unable to delete router rule.')) - try: - if 'nexthops' not in data: - data['nexthops'] = '' - if data['source'] == '0.0.0.0/0': - data['source'] = 'any' - if data['destination'] == '0.0.0.0/0': - data['destination'] = 'any' - rule = {'action': data['action'], - 'source': data['source'], - 'destination': data['destination'], - 'nexthops': data['nexthops'].split(',')} - rulemanager.add_rule(request, - router_id=data['router_id'], - newrule=rule) - msg = _('Router rule added') - LOG.debug(msg) - messages.success(request, msg) - return True - except Exception as e: - msg = _('Failed to add router rule %s') % e - LOG.info(msg) - messages.error(request, msg) - redirect = reverse(self.failure_url, args=[data['router_id']]) - exceptions.handle(request, msg, redirect=redirect) diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/rulemanager.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/rulemanager.py deleted file mode 100644 index 35c6b1c7e..000000000 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/rulemanager.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2013, Big Switch Networks -# -# 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from openstack_dashboard.api import neutron as api - -LOG = logging.getLogger(__name__) - - -class RuleObject(dict): - def __init__(self, rule): - # ID is constructed from source and destination because the - # database ID from neutron changes on every update, making a list of - # sequential operations based on the DB ID invalid after the first one - # occurs (e.g. deleting multiple from the table - rule['id'] = rule['source'] + rule['destination'] - super(RuleObject, self).__init__(rule) - # Horizon references id property for table operations - self.id = rule['id'] - # Flatten into csv for display - self.nexthops = ','.join(rule['nexthops']) - - -def routerrule_list(request, **params): - if 'router_id' in params: - params['device_id'] = params['router_id'] - if 'router' in request.META: - router = request.META['router'] - else: - router = api.router_get(request, params['device_id']) - try: - rules = router.router_rules - except AttributeError: - return (False, []) - return (True, rules) - - -def remove_rules(request, rule_ids, **kwargs): - LOG.debug("remove_rules(): param=%s", kwargs) - router_id = kwargs['router_id'] - if 'reset_rules' in kwargs: - newrules = [{'source': 'any', 'destination': 'any', - 'action': 'permit'}] - else: - supported, currentrules = routerrule_list(request, **kwargs) - if not supported: - LOG.error("router rules not supported by router %s" % router_id) - return - newrules = [] - for oldrule in currentrules: - if RuleObject(oldrule).id not in rule_ids: - newrules.append(oldrule) - body = {'router_rules': format_for_api(newrules)} - new = api.router_update(request, router_id, **body) - if 'router' in request.META: - request.META['router'] = new - return new - - -def add_rule(request, router_id, newrule, **kwargs): - body = {'router_rules': []} - kwargs['router_id'] = router_id - supported, currentrules = routerrule_list(request, **kwargs) - if not supported: - LOG.error("router rules not supported by router %s" % router_id) - return - body['router_rules'] = format_for_api([newrule] + currentrules) - new = api.router_update(request, router_id, **body) - if 'router' in request.META: - request.META['router'] = new - return new - - -def format_for_api(rules): - apiformrules = [] - for r in rules: - # make a copy so we don't damage original dict in rules - flattened = r.copy() - # nexthops should only be present if there are nexthop addresses - if 'nexthops' in flattened: - cleanednh = [nh.strip() - for nh in flattened['nexthops'] - if nh.strip()] - if cleanednh: - flattened['nexthops'] = '+'.join(cleanednh) - else: - del flattened['nexthops'] - if 'id' in flattened: - del flattened['id'] - apiformrules.append(flattened) - return apiformrules diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tables.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tables.py deleted file mode 100644 index 0a8f9a79d..000000000 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tables.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2013, Big Switch Networks, 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy - -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import rulemanager -from openstack_dashboard import policy - -from horizon import tables - - -class AddRouterRule(policy.PolicyTargetMixin, tables.LinkAction): - name = "create" - verbose_name = _("Add Router Rule") - url = "horizon:project:routers:addrouterrule" - classes = ("ajax-modal",) - icon = "plus" - policy_rules = (("network", "update_router"),) - - def get_link_url(self, datum=None): - router_id = self.table.kwargs['router_id'] - return reverse(self.url, args=(router_id,)) - - -class RemoveRouterRule(policy.PolicyTargetMixin, tables.DeleteAction): - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Router Rule", - u"Delete Router Rules", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Deleted Router Rule", - u"Deleted Router Rules", - count - ) - - failure_url = 'horizon:project:routers:detail' - policy_rules = (("network", "update_router"),) - - def delete(self, request, obj_id): - router_id = self.table.kwargs['router_id'] - rulemanager.remove_rules(request, [obj_id], - router_id=router_id) - - -class RouterRulesTable(tables.DataTable): - source = tables.Column("source", verbose_name=_("Source CIDR")) - destination = tables.Column("destination", - verbose_name=_("Destination CIDR")) - action = tables.Column("action", verbose_name=_("Action")) - nexthops = tables.Column("nexthops", verbose_name=_("Next Hops")) - - def get_object_display(self, rule): - return "(%(action)s) %(source)s -> %(destination)s" % rule - - class Meta(object): - name = "routerrules" - verbose_name = _("Router Rules") - table_actions = (AddRouterRule, RemoveRouterRule) - row_actions = (RemoveRouterRule, ) diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py deleted file mode 100644 index b146b1c94..000000000 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/tabs.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright 2013 -# -# 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from django import template -from django.template.loader import render_to_string -from django.utils.translation import ugettext_lazy as _ - -from horizon import tabs - -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import rulemanager -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import tables as rrtbl - - -class RouterRulesTab(tabs.TableTab): - table_classes = (rrtbl.RouterRulesTable,) - name = _("Router Rules") - slug = "routerrules" - template_name = "horizon/common/_detail_table.html" - - def allowed(self, request): - try: - getattr(self.tab_group.kwargs['router'], 'router_rules') - return True - except Exception: - return False - - def get_routerrules_data(self): - try: - routerrules = getattr(self.tab_group.kwargs['router'], - 'router_rules') - except Exception: - routerrules = [] - return [rulemanager.RuleObject(r) for r in routerrules] - - def post(self, request, *args, **kwargs): - if request.POST['action'] == 'routerrules__resetrules': - kwargs['reset_rules'] = True - rulemanager.remove_rules(request, [], **kwargs) - self.tab_group.kwargs['router'] = \ - api.neutron.router_get(request, kwargs['router_id']) - - -class RulesGridTab(tabs.Tab): - name = _("Router Rules Grid") - slug = "rulesgrid" - template_name = ("project/routers/extensions/routerrules/grid.html") - - def allowed(self, request): - try: - getattr(self.tab_group.kwargs['router'], 'router_rules') - return True - except Exception: - return False - - def render(self): - context = template.RequestContext(self.request) - return render_to_string(self.get_template_name(self.request), - self.data, context_instance=context) - - def get_context_data(self, request, **kwargs): - data = {'router': {'id': - self.tab_group.kwargs['router_id']}} - self.request = request - rules, supported = self.get_routerrules_data(checksupport=True) - if supported: - data["rulesmatrix"] = self.get_routerrulesgrid_data(rules) - return data - - def get_routerrulesgrid_data(self, rules): - ports = self.tab_group.kwargs['ports'] - networks = api.neutron.network_list_for_tenant( - self.request, self.request.user.tenant_id) - netnamemap = {} - subnetmap = {} - for n in networks: - netnamemap[n['id']] = n.name_or_id - for s in n.subnets: - subnetmap[s.id] = {'name': s.name, - 'cidr': s.cidr} - - matrix = [] - subnets = [] - for port in ports: - for ip in port['fixed_ips']: - if ip['subnet_id'] not in subnetmap: - continue - sub = {'ip': ip['ip_address'], - 'subnetid': ip['subnet_id'], - 'subnetname': subnetmap[ip['subnet_id']]['name'], - 'networkid': port['network_id'], - 'networkname': netnamemap[port['network_id']], - 'cidr': subnetmap[ip['subnet_id']]['cidr']} - subnets.append(sub) - subnets.append({'ip': '0.0.0.0', - 'subnetid': 'external', - 'subnetname': '', - 'networkname': 'external', - 'networkid': 'external', - 'cidr': '0.0.0.0/0'}) - subnets.append({'ip': '0.0.0.0', - 'subnetid': 'any', - 'subnetname': '', - 'networkname': 'any', - 'networkid': 'any', - 'cidr': '0.0.0.0/0'}) - for source in subnets: - row = {'source': dict(source), - 'targets': []} - for target in subnets: - target.update(self._get_subnet_connectivity( - source, target, rules)) - row['targets'].append(dict(target)) - matrix.append(row) - return matrix - - def _get_subnet_connectivity(self, src_sub, dst_sub, rules): - v4_any_words = ['external', 'any'] - connectivity = {'reachable': '', - 'inverse_rule': {}, - 'rule_to_delete': False} - src = src_sub['cidr'] - dst = dst_sub['cidr'] - # differentiate between external and any - src_rulename = src_sub['subnetid'] if src == '0.0.0.0/0' else src - dst_rulename = dst_sub['subnetid'] if dst == '0.0.0.0/0' else dst - if str(src) == str(dst): - connectivity['reachable'] = 'full' - return connectivity - matchingrules = [] - - for rule in rules: - rd = rule['destination'] - if rule['destination'] in v4_any_words: - rd = '0.0.0.0/0' - rs = rule['source'] - if rule['source'] in v4_any_words: - rs = '0.0.0.0/0' - rs = netaddr.IPNetwork(rs) - src = netaddr.IPNetwork(src) - rd = netaddr.IPNetwork(rd) - dst = netaddr.IPNetwork(dst) - # check if cidrs are affected by rule first - if (int(dst.network) >= int(rd[-1]) or - int(dst[-1]) <= int(rd.network) or - int(src.network) >= int(rs[-1]) or - int(src[-1]) <= int(rs.network)): - continue - - # skip matching rules for 'any' and 'external' networks - if (str(dst) == '0.0.0.0/0' and str(rd) != '0.0.0.0/0'): - continue - if (str(src) == '0.0.0.0/0' and str(rs) != '0.0.0.0/0'): - continue - - # external network rules only affect external traffic - if (rule['source'] == 'external' and - src_rulename not in v4_any_words): - continue - if (rule['destination'] == 'external' and - dst_rulename not in v4_any_words): - continue - - match = {'bitsinsrc': rs.prefixlen, - 'bitsindst': rd.prefixlen, - 'rule': rule} - matchingrules.append(match) - - if not matchingrules: - connectivity['reachable'] = 'none' - connectivity['inverse_rule'] = {'source': src_rulename, - 'destination': dst_rulename, - 'action': 'permit'} - return connectivity - - sortedrules = sorted(matchingrules, - key=lambda k: (k['bitsinsrc'], k['bitsindst']), - reverse=True) - match = sortedrules[0] - if (match['bitsinsrc'] > src.prefixlen or - match['bitsindst'] > dst.prefixlen): - connectivity['reachable'] = 'partial' - connectivity['conflicting_rule'] = match['rule'] - return connectivity - - if (match['rule']['source'] == src_rulename and - match['rule']['destination'] == dst_rulename): - connectivity['rule_to_delete'] = match['rule'] - - if match['rule']['action'] == 'permit': - connectivity['reachable'] = 'full' - inverseaction = 'deny' - else: - connectivity['reachable'] = 'none' - inverseaction = 'permit' - connectivity['inverse_rule'] = {'source': src_rulename, - 'destination': dst_rulename, - 'action': inverseaction} - return connectivity - - def get_routerrules_data(self, checksupport=False): - try: - routerrules = getattr(self.tab_group.kwargs['router'], - 'router_rules') - supported = True - except Exception: - routerrules = [] - supported = False - - if checksupport: - return routerrules, supported - return routerrules diff --git a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/views.py b/openstack_dashboard/dashboards/project/routers/extensions/routerrules/views.py deleted file mode 100644 index 33e2707b3..000000000 --- a/openstack_dashboard/dashboards/project/routers/extensions/routerrules/views.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013, Big Switch Networks -# -# 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 -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon.utils import memoized - -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import forms as rrforms - - -class AddRouterRuleView(forms.ModalFormView): - form_class = rrforms.AddRouterRule - template_name = 'project/routers/extensions/routerrules/create.html' - success_url = 'horizon:project:routers:detail' - failure_url = 'horizon:project:routers:detail' - page_title = _("Add Router Rule") - - def get_success_url(self): - return reverse(self.success_url, - args=(self.kwargs['router_id'],)) - - @memoized.memoized_method - def get_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(AddRouterRuleView, self).get_context_data(**kwargs) - context['router'] = self.get_object() - return context - - def get_initial(self): - router = self.get_object() - # store the router in the request so the rule manager doesn't have - # to request it again from the API - self.request.META['router'] = router - return {"router_id": self.kwargs['router_id'], - "router_name": router.name_or_id} diff --git a/openstack_dashboard/dashboards/project/routers/tabs.py b/openstack_dashboard/dashboards/project/routers/tabs.py index bec790364..0e6fc4e89 100644 --- a/openstack_dashboard/dashboards/project/routers/tabs.py +++ b/openstack_dashboard/dashboards/project/routers/tabs.py @@ -19,8 +19,6 @@ from horizon import tabs from openstack_dashboard import api from openstack_dashboard.dashboards.project.routers.extensions.extraroutes\ import tabs as er_tabs -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import tabs as rr_tabs from openstack_dashboard.dashboards.project.routers.ports import tables as ptbl @@ -48,6 +46,5 @@ class InterfacesTab(tabs.TableTab): class RouterDetailTabs(tabs.TabGroup): slug = "router_details" - tabs = (OverviewTab, InterfacesTab, er_tabs.ExtraRoutesTab, - rr_tabs.RulesGridTab, rr_tabs.RouterRulesTab) + tabs = (OverviewTab, InterfacesTab, er_tabs.ExtraRoutesTab) sticky = True diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/_create.html b/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/_create.html deleted file mode 100644 index 27ee8c75c..000000000 --- a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/_create.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}add_routerrule_form{% endblock %} -{% block form_action %}{% url 'horizon:project:routers:addrouterrule' router.id %} -{% endblock %} - -{% block modal-header %}{% trans "Add Router Rule" %}{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

- {% trans "Routing rules to apply to router. Rules are matched by most specific source first and then by most specific destination." %}
- {% trans "The next hop addresses can be used to override the router used by the client." %} -

-
-{% endblock %} diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/create.html b/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/create.html deleted file mode 100644 index 28bde236c..000000000 --- a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/create.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Add Router Rule" %}{% endblock %} - -{% block main %} - {% include "project/routers/extensions/routerrules/_create.html" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/grid.html b/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/grid.html deleted file mode 100644 index 160a568c1..000000000 --- a/openstack_dashboard/dashboards/project/routers/templates/routers/extensions/routerrules/grid.html +++ /dev/null @@ -1,156 +0,0 @@ -{% load i18n %} - -{% block main %} - -
- - - - - - - - - {% with src=rulesmatrix|first %} - {% for dest in src.targets %} - - {% endfor %} - {% endwith %} - - - -{% for row in rulesmatrix %} - - - {% for dest in row.targets %} - - {% endfor %} - {% endfor %} - - - - - - - -
-

{% trans "Router Rule Grid" %}

-
-
- {% csrf_token %} - - -
-
-
{% trans "Destination" %}→
↓{% trans "Source" %}
- {{ dest.networkname }}
- {% if dest.subnetname|length > 0 %} - {% blocktrans trimmed with dest_subnetname=dest.subnetname %} - Subnet: {{ dest_subnetname }}{% endblocktrans %}
- {% endif %} - {{ dest.cidr }} -
-{{ row.source.networkname }} -{% if row.source.subnetname|length > 0 %} -
- {% blocktrans trimmed with row_source_subnetname=row.source.subnetname %} - Subnet: {{ row_source_subnetname }}{% endblocktrans %} -{% endif %} -
-{{ row.source.cidr }} -
-
-
- {% csrf_token %} - - - - - - {% if dest.rule_to_delete %} -
- {% endif %} - {% if dest.reachable == 'none' %} -
- -
- {% elif dest.reachable == 'full' %} -
- - {% if not dest.cidr == row.source.cidr %} - - {% else %} -         - {% endif %} -
- {% else %} - - - {% endif %} -
-
- -
-

{% trans "Description" %}

-

{% blocktrans trimmed %} - The color and icon of an intersection indicates whether or not traffic is - permitted from the source (row) to the destination (column). - Clicking the button in the intersection - will install a rule to switch the traffic behavior.
- Note: Rules only affect one direction of traffic. - The opposite direction is outlined when hovering over an intersection. - {% endblocktrans %}

-
- -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/routers/tests.py b/openstack_dashboard/dashboards/project/routers/tests.py index cd247ec81..5fc49d87e 100644 --- a/openstack_dashboard/dashboards/project/routers/tests.py +++ b/openstack_dashboard/dashboards/project/routers/tests.py @@ -21,8 +21,6 @@ from mox3.mox import IsA # noqa import six from openstack_dashboard import api -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import rulemanager from openstack_dashboard.test import helpers as test from openstack_dashboard.usage import quotas @@ -701,150 +699,6 @@ class RouterActionTests(RouterMixin, test.TestCase): self.assertRedirectsNoFollow(res, detail_url) -class RouterRuleTests(RouterMixin, test.TestCase): - DASHBOARD = 'project' - INDEX_URL = reverse('horizon:%s:routers:index' % DASHBOARD) - DETAIL_PATH = 'horizon:%s:routers:detail' % DASHBOARD - - def test_extension_hides_without_rules(self): - router = self.routers.first() - res = self._get_detail(router) - - self.assertTemplateUsed(res, 'horizon/common/_detail.html') - self.assertTemplateNotUsed( - res, - '%s/routers/extensions/routerrules/grid.html' % self.DASHBOARD) - - @test.create_stubs({api.neutron: ('network_list',)}) - def test_routerrule_detail(self): - router = self.routers_with_rules.first() - if self.DASHBOARD == 'project': - api.neutron.network_list( - IsA(http.HttpRequest), - shared=False, - tenant_id=router['tenant_id']).AndReturn(self.networks.list()) - api.neutron.network_list( - IsA(http.HttpRequest), - shared=True).AndReturn([]) - res = self._get_detail(router) - - self.assertTemplateUsed(res, 'horizon/common/_detail.html') - if self.DASHBOARD == 'project': - self.assertTemplateUsed( - res, - '%s/routers/extensions/routerrules/grid.html' % self.DASHBOARD) - rules = res.context['routerrules_table'].data - self.assertItemsEqual(rules, router['router_rules']) - - def _test_router_addrouterrule(self, raise_error=False): - pre_router = self.routers_with_rules.first() - post_router = copy.deepcopy(pre_router) - rule = {'source': '1.2.3.4/32', 'destination': '4.3.2.1/32', 'id': 99, - 'action': 'permit', 'nexthops': ['1.1.1.1', '2.2.2.2']} - post_router['router_rules'].insert(0, rule) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(pre_router) - params = {} - params['router_rules'] = rulemanager.format_for_api( - post_router['router_rules']) - router_update = api.neutron.router_update(IsA(http.HttpRequest), - pre_router.id, **params) - if raise_error: - router_update.AndRaise(self.exceptions.neutron) - else: - router_update.AndReturn({'router': post_router}) - self.mox.ReplayAll() - - form_data = {'router_id': pre_router.id, - 'source': rule['source'], - 'destination': rule['destination'], - 'action': rule['action'], - 'nexthops': ','.join(rule['nexthops'])} - - url = reverse('horizon:%s:routers:addrouterrule' % self.DASHBOARD, - args=[pre_router.id]) - res = self.client.post(url, form_data) - self.assertNoFormErrors(res) - detail_url = reverse(self.DETAIL_PATH, args=[pre_router.id]) - self.assertRedirectsNoFollow(res, detail_url) - - @test.create_stubs({api.neutron: ('router_get', - 'router_update')}) - def test_router_addrouterrule(self): - self._test_router_addrouterrule() - - @test.create_stubs({api.neutron: ('router_get', - 'router_update')}) - def test_router_addrouterrule_exception(self): - self._test_router_addrouterrule(raise_error=True) - - @test.create_stubs({api.neutron: ('router_get', 'router_update', - 'port_list', 'network_get', - 'is_extension_supported')}) - def test_router_removerouterrule(self): - pre_router = self.routers_with_rules.first() - post_router = copy.deepcopy(pre_router) - rule = post_router['router_rules'].pop() - api.neutron.is_extension_supported(IsA(http.HttpRequest), 'extraroute')\ - .AndReturn(False) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(pre_router) - params = {} - params['router_rules'] = rulemanager.format_for_api( - post_router['router_rules']) - router_update = api.neutron.router_update(IsA(http.HttpRequest), - pre_router.id, **params) - router_update.AndReturn({'router': post_router}) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(pre_router) - api.neutron.port_list(IsA(http.HttpRequest), - device_id=pre_router.id)\ - .AndReturn([self.ports.first()]) - self._mock_external_network_get(pre_router) - self.mox.ReplayAll() - form_rule_id = rule['source'] + rule['destination'] - form_data = {'router_id': pre_router.id, - 'action': 'routerrules__delete__%s' % form_rule_id} - url = reverse(self.DETAIL_PATH, args=[pre_router.id]) - res = self.client.post(url, form_data) - self.assertNoFormErrors(res) - - @test.create_stubs({api.neutron: ('router_get', 'router_update', - 'network_list', 'port_list', - 'network_get', - 'is_extension_supported')}) - def test_router_resetrouterrules(self): - pre_router = self.routers_with_rules.first() - post_router = copy.deepcopy(pre_router) - default_rules = [{'source': 'any', 'destination': 'any', - 'action': 'permit', 'nexthops': [], 'id': '2'}] - del post_router['router_rules'][:] - post_router['router_rules'].extend(default_rules) - api.neutron.is_extension_supported(IsA(http.HttpRequest), 'extraroute')\ - .AndReturn(False) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(post_router) - params = {} - params['router_rules'] = rulemanager.format_for_api( - post_router['router_rules']) - router_update = api.neutron.router_update(IsA(http.HttpRequest), - pre_router.id, **params) - router_update.AndReturn({'router': post_router}) - api.neutron.port_list(IsA(http.HttpRequest), - device_id=pre_router.id)\ - .AndReturn([self.ports.first()]) - self._mock_external_network_get(pre_router) - self._mock_network_list(pre_router['tenant_id']) - api.neutron.router_get(IsA(http.HttpRequest), - pre_router.id).AndReturn(post_router) - self.mox.ReplayAll() - form_data = {'router_id': pre_router.id, - 'action': 'routerrules__resetrules'} - url = reverse(self.DETAIL_PATH, args=[pre_router.id]) - res = self.client.post(url, form_data) - self.assertNoFormErrors(res) - - class RouterRouteTests(RouterMixin, test.TestCase): DASHBOARD = 'project' INDEX_URL = reverse('horizon:%s:routers:index' % DASHBOARD) diff --git a/openstack_dashboard/dashboards/project/routers/urls.py b/openstack_dashboard/dashboards/project/routers/urls.py index a597e8eb7..40ac695cd 100644 --- a/openstack_dashboard/dashboards/project/routers/urls.py +++ b/openstack_dashboard/dashboards/project/routers/urls.py @@ -16,8 +16,6 @@ from django.conf.urls import url from openstack_dashboard.dashboards.project.routers.extensions.extraroutes\ import views as er_views -from openstack_dashboard.dashboards.project.routers.extensions.routerrules\ - import views as rr_views from openstack_dashboard.dashboards.project.routers.ports \ import views as port_views from openstack_dashboard.dashboards.project.routers import views @@ -38,9 +36,6 @@ urlpatterns = [ url(ROUTER_URL % 'addinterface', port_views.AddInterfaceView.as_view(), name='addinterface'), - url(ROUTER_URL % 'addrouterrule', - rr_views.AddRouterRuleView.as_view(), - name='addrouterrule'), url(ROUTER_URL % 'addrouterroute', er_views.AddRouterRouteView.as_view(), name='addrouterroute'), diff --git a/releasenotes/notes/bp-horizon-vendor-split-4451bc1988485957.yaml b/releasenotes/notes/bp-horizon-vendor-split-4451bc1988485957.yaml new file mode 100644 index 000000000..29f713701 --- /dev/null +++ b/releasenotes/notes/bp-horizon-vendor-split-4451bc1988485957.yaml @@ -0,0 +1,6 @@ +--- +deprecations: + - Router rules is a horizon extension provided by Big Switch Networks. + As part of the horizon-vendor-split work, we drop the extension from upstream horizon. + It is now available as a separate plugin at https://github.com/bigswitch/horizon-bsn +