1# Copyright 2012, Nachi Ueno, NTT MCL, Inc. 2# Copyright 2013, Big Switch Networks, Inc. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); you may 5# not use this file except in compliance with the License. You may obtain 6# a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# License for the specific language governing permissions and limitations 14# under the License. 15 16""" 17Views for managing Neutron Routers. 18""" 19 20from collections import OrderedDict 21 22from django.urls import reverse 23from django.urls import reverse_lazy 24from django.utils.translation import pgettext_lazy 25from django.utils.translation import ugettext_lazy as _ 26 27from horizon import exceptions 28from horizon import forms 29from horizon import messages 30from horizon import tables 31from horizon import tabs 32from horizon.utils import memoized 33 34from openstack_dashboard import api 35from openstack_dashboard.utils import filters 36 37from openstack_dashboard.dashboards.project.routers\ 38 import forms as project_forms 39from openstack_dashboard.dashboards.project.routers import tables as rtables 40from openstack_dashboard.dashboards.project.routers import tabs as rdtabs 41 42 43class IndexView(tables.DataTableView): 44 table_class = rtables.RoutersTable 45 page_title = _("Routers") 46 FILTERS_MAPPING = {'admin_state_up': {_("up"): True, _("down"): False}} 47 48 def _get_routers(self, search_opts=None): 49 try: 50 search_opts = self.get_filters( 51 filters=search_opts, filters_map=self.FILTERS_MAPPING) 52 tenant_id = self.request.user.tenant_id 53 routers = api.neutron.router_list(self.request, 54 tenant_id=tenant_id, 55 **search_opts) 56 except Exception: 57 routers = [] 58 exceptions.handle(self.request, 59 _('Unable to retrieve router list.')) 60 61 ext_net_dict = self._list_external_networks() 62 63 for r in routers: 64 r.name = r.name_or_id 65 self._set_external_network(r, ext_net_dict) 66 return routers 67 68 def get_data(self): 69 routers = self._get_routers() 70 return routers 71 72 def _list_external_networks(self): 73 try: 74 search_opts = {'router:external': True} 75 ext_nets = api.neutron.network_list(self.request, 76 **search_opts) 77 ext_net_dict = OrderedDict((n['id'], n.name_or_id) 78 for n in ext_nets) 79 except Exception: 80 msg = _('Unable to retrieve a list of external networks.') 81 exceptions.handle(self.request, msg) 82 ext_net_dict = {} 83 return ext_net_dict 84 85 def _set_external_network(self, router, ext_net_dict): 86 gateway_info = router.external_gateway_info 87 if gateway_info: 88 ext_net_id = gateway_info['network_id'] 89 if ext_net_id in ext_net_dict: 90 gateway_info['network'] = ext_net_dict[ext_net_id] 91 else: 92 msg_params = {'ext_net_id': ext_net_id, 'router_id': router.id} 93 msg = _('External network "%(ext_net_id)s" expected but not ' 94 'found for router "%(router_id)s".') % msg_params 95 messages.error(self.request, msg) 96 # gateway_info['network'] is just the network name, so putting 97 # in a smallish error message in the table is reasonable. 98 # Translators: The usage is "<UUID of ext_net> (Not Found)" 99 gateway_info['network'] = pgettext_lazy( 100 'External network not found', 101 '%s (Not Found)') % ext_net_id 102 103 104class DetailView(tabs.TabbedTableView): 105 tab_group_class = rdtabs.RouterDetailTabs 106 template_name = 'horizon/common/_detail.html' 107 failure_url = reverse_lazy('horizon:project:routers:index') 108 network_url = 'horizon:project:networks:detail' 109 page_title = "{{ router.name|default:router.id }}" 110 111 @memoized.memoized_method 112 def _get_data(self): 113 try: 114 router_id = self.kwargs['router_id'] 115 router = api.neutron.router_get(self.request, router_id) 116 router.set_id_as_name_if_empty(length=0) 117 except Exception: 118 msg = _('Unable to retrieve details for router "%s".') \ 119 % router_id 120 exceptions.handle(self.request, msg, redirect=self.failure_url) 121 if router.external_gateway_info: 122 ext_net_id = router.external_gateway_info['network_id'] 123 router.external_gateway_info['network_url'] = reverse( 124 self.network_url, args=[ext_net_id]) 125 try: 126 ext_net = api.neutron.network_get(self.request, ext_net_id, 127 expand_subnet=False) 128 ext_net.set_id_as_name_if_empty(length=0) 129 router.external_gateway_info['network'] = ext_net.name 130 except Exception: 131 msg = _('Unable to retrieve an external network "%s".') \ 132 % ext_net_id 133 exceptions.handle(self.request, msg) 134 router.external_gateway_info['network'] = ext_net_id 135 return router 136 137 @memoized.memoized_method 138 def _get_ports(self): 139 try: 140 ports = api.neutron.port_list(self.request, 141 device_id=self.kwargs['router_id']) 142 except Exception: 143 ports = [] 144 msg = _('Unable to retrieve port details.') 145 exceptions.handle(self.request, msg) 146 return ports 147 148 def get_context_data(self, **kwargs): 149 context = super().get_context_data(**kwargs) 150 router = self._get_data() 151 table = rtables.RoutersTable(self.request) 152 153 context["router"] = router 154 context["url"] = self.failure_url 155 context["actions"] = table.render_row_actions(router) 156 context['dvr_supported'] = api.neutron.get_feature_permission( 157 self.request, "dvr", "get") 158 context['ha_supported'] = api.neutron.get_feature_permission( 159 self.request, "l3-ha", "get") 160 choices = rtables.STATUS_DISPLAY_CHOICES 161 router.status_label = filters.get_display_label(choices, router.status) 162 choices = rtables.ADMIN_STATE_DISPLAY_CHOICES 163 router.admin_state_label = ( 164 filters.get_display_label(choices, router.admin_state)) 165 return context 166 167 def get_tabs(self, request, *args, **kwargs): 168 router = self._get_data() 169 ports = self._get_ports() 170 return self.tab_group_class(request, router=router, 171 ports=ports, **kwargs) 172 173 174class CreateView(forms.ModalFormView): 175 form_class = project_forms.CreateForm 176 form_id = "create_router_form" 177 template_name = 'project/routers/create.html' 178 success_url = reverse_lazy("horizon:project:routers:index") 179 page_title = _("Create Router") 180 submit_label = _("Create Router") 181 submit_url = reverse_lazy("horizon:project:routers:create") 182 183 def get_context_data(self, **kwargs): 184 context = super().get_context_data(**kwargs) 185 context['enable_snat_allowed'] = self.initial['enable_snat_allowed'] 186 return context 187 188 def get_initial(self): 189 enable_snat_allowed = api.neutron.get_feature_permission( 190 self.request, 'ext-gw-mode', 'create_router_enable_snat') 191 self.initial['enable_snat_allowed'] = enable_snat_allowed 192 return super().get_initial() 193 194 195class UpdateView(forms.ModalFormView): 196 form_class = project_forms.UpdateForm 197 form_id = "update_router_form" 198 template_name = 'project/routers/update.html' 199 success_url = reverse_lazy("horizon:project:routers:index") 200 page_title = _("Edit Router") 201 submit_label = _("Save Changes") 202 submit_url = "horizon:project:routers:update" 203 204 def get_context_data(self, **kwargs): 205 context = super().get_context_data(**kwargs) 206 args = (self.kwargs['router_id'],) 207 context["router_id"] = self.kwargs['router_id'] 208 context['submit_url'] = reverse(self.submit_url, args=args) 209 return context 210 211 def _get_object(self, *args, **kwargs): 212 router_id = self.kwargs['router_id'] 213 try: 214 return api.neutron.router_get(self.request, router_id) 215 except Exception: 216 redirect = self.success_url 217 msg = _('Unable to retrieve router details.') 218 exceptions.handle(self.request, msg, redirect=redirect) 219 220 def get_initial(self): 221 router = self._get_object() 222 initial = {'router_id': router['id'], 223 'tenant_id': router['tenant_id'], 224 'name': router['name'], 225 'admin_state': router['admin_state_up']} 226 if hasattr(router, 'distributed'): 227 initial['mode'] = ('distributed' if router.distributed 228 else 'centralized') 229 if hasattr(router, 'ha'): 230 initial['ha'] = router.ha 231 return initial 232