OpenStack Dashboard (Horizon)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
7.8KB

  1. # Copyright 2012 Nebula, Inc.
  2. # Copyright (c) 2012 X.commerce, a business unit of eBay 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. import logging
  16. from django.core.urlresolvers import reverse
  17. from django import shortcuts
  18. from django.utils.http import urlencode
  19. from django.utils.translation import pgettext_lazy
  20. from django.utils.translation import string_concat # noqa
  21. from django.utils.translation import ugettext_lazy as _
  22. from django.utils.translation import ungettext_lazy
  23. from horizon import exceptions
  24. from horizon import messages
  25. from horizon import tables
  26. from openstack_dashboard import api
  27. from openstack_dashboard import policy
  28. from openstack_dashboard.usage import quotas
  29. from openstack_dashboard.utils import filters
  30. LOG = logging.getLogger(__name__)
  31. class AllocateIP(tables.LinkAction):
  32. name = "allocate"
  33. verbose_name = _("Allocate IP To Project")
  34. classes = ("ajax-modal",)
  35. icon = "link"
  36. url = "horizon:project:floating_ips:allocate"
  37. def single(self, data_table, request, *args):
  38. return shortcuts.redirect('horizon:project:floating_ips:index')
  39. def allowed(self, request, fip=None):
  40. usages = quotas.tenant_quota_usages(request)
  41. if usages['floating_ips']['available'] <= 0:
  42. if "disabled" not in self.classes:
  43. self.classes = [c for c in self.classes] + ['disabled']
  44. self.verbose_name = string_concat(self.verbose_name, ' ',
  45. _("(Quota exceeded)"))
  46. else:
  47. self.verbose_name = _("Allocate IP To Project")
  48. classes = [c for c in self.classes if c != "disabled"]
  49. self.classes = classes
  50. if api.base.is_service_enabled(request, "network"):
  51. policy_rules = (("network", "create_floatingip"),)
  52. else:
  53. policy_rules = (("compute", "compute_extension:floating_ips"),
  54. ("compute", "network:allocate_floating_ip"),)
  55. return policy.check(policy_rules, request)
  56. class ReleaseIPs(tables.BatchAction):
  57. name = "release"
  58. action_type = "danger"
  59. icon = "unlink"
  60. help_text = _("Once a floating IP is released, there is"
  61. " no guarantee the same IP can be allocated again.")
  62. @staticmethod
  63. def action_present(count):
  64. return ungettext_lazy(
  65. u"Release Floating IP",
  66. u"Release Floating IPs",
  67. count
  68. )
  69. @staticmethod
  70. def action_past(count):
  71. return ungettext_lazy(
  72. u"Released Floating IP",
  73. u"Released Floating IPs",
  74. count
  75. )
  76. def allowed(self, request, fip=None):
  77. if api.base.is_service_enabled(request, "network"):
  78. policy_rules = (("network", "delete_floatingip"),)
  79. else:
  80. policy_rules = (("compute", "compute_extension:floating_ips"),
  81. ("compute", "network:release_floating_ip"),)
  82. return policy.check(policy_rules, request)
  83. def action(self, request, obj_id):
  84. api.network.tenant_floating_ip_release(request, obj_id)
  85. class AssociateIP(tables.LinkAction):
  86. name = "associate"
  87. verbose_name = _("Associate")
  88. url = "horizon:project:floating_ips:associate"
  89. classes = ("ajax-modal",)
  90. icon = "link"
  91. def allowed(self, request, fip):
  92. if api.base.is_service_enabled(request, "network"):
  93. policy_rules = (("network", "update_floatingip"),)
  94. else:
  95. policy_rules = (("compute", "compute_extension:floating_ips"),
  96. ("compute", "network:associate_floating_ip"),)
  97. return not fip.port_id and policy.check(policy_rules, request)
  98. def get_link_url(self, datum):
  99. base_url = reverse(self.url)
  100. params = urlencode({"ip_id": self.table.get_object_id(datum)})
  101. return "?".join([base_url, params])
  102. class DisassociateIP(tables.Action):
  103. name = "disassociate"
  104. verbose_name = _("Disassociate")
  105. classes = ("btn-disassociate",)
  106. icon = "unlink"
  107. action_type = "danger"
  108. def allowed(self, request, fip):
  109. if api.base.is_service_enabled(request, "network"):
  110. policy_rules = (("network", "update_floatingip"),)
  111. else:
  112. policy_rules = (("compute", "compute_extension:floating_ips"),
  113. ("compute", "network:disassociate_floating_ip"),)
  114. return fip.port_id and policy.check(policy_rules, request)
  115. def single(self, table, request, obj_id):
  116. try:
  117. fip = table.get_object_by_id(filters.get_int_or_uuid(obj_id))
  118. api.network.floating_ip_disassociate(request, fip.id)
  119. LOG.info('Disassociating Floating IP "%s".' % obj_id)
  120. messages.success(request,
  121. _('Successfully disassociated Floating IP: %s')
  122. % fip.ip)
  123. except Exception:
  124. exceptions.handle(request,
  125. _('Unable to disassociate floating IP.'))
  126. return shortcuts.redirect('horizon:project:floating_ips:index')
  127. def get_instance_info(fip):
  128. if fip.instance_type == 'compute':
  129. return (_("%(instance_name)s %(fixed_ip)s")
  130. % {'instance_name': getattr(fip, "instance_name", ''),
  131. 'fixed_ip': fip.fixed_ip})
  132. elif fip.instance_type == 'loadbalancer':
  133. return _("Load Balancer VIP %s") % fip.fixed_ip
  134. elif fip.instance_type:
  135. return fip.fixed_ip
  136. else:
  137. return None
  138. def get_instance_link(datum):
  139. if getattr(datum, 'instance_id'):
  140. return reverse("horizon:project:instances:detail",
  141. args=(datum.instance_id,))
  142. else:
  143. return None
  144. STATUS_DISPLAY_CHOICES = (
  145. ("active", pgettext_lazy("Current status of a Floating IP", u"Active")),
  146. ("down", pgettext_lazy("Current status of a Floating IP", u"Down")),
  147. ("error", pgettext_lazy("Current status of a Floating IP", u"Error")),
  148. )
  149. class FloatingIPsTable(tables.DataTable):
  150. STATUS_CHOICES = (
  151. ("active", True),
  152. ("down", True),
  153. ("error", False)
  154. )
  155. ip = tables.Column("ip",
  156. verbose_name=_("IP Address"),
  157. attrs={'data-type': "ip"})
  158. fixed_ip = tables.Column(get_instance_info,
  159. link=get_instance_link,
  160. verbose_name=_("Mapped Fixed IP Address"))
  161. pool = tables.Column("pool_name",
  162. verbose_name=_("Pool"))
  163. status = tables.Column("status",
  164. verbose_name=_("Status"),
  165. status=True,
  166. status_choices=STATUS_CHOICES,
  167. display_choices=STATUS_DISPLAY_CHOICES)
  168. def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs):
  169. super(FloatingIPsTable, self).__init__(
  170. request, data=data, needs_form_wrapper=needs_form_wrapper,
  171. **kwargs)
  172. if not api.base.is_service_enabled(request, 'network'):
  173. del self.columns['status']
  174. def sanitize_id(self, obj_id):
  175. return filters.get_int_or_uuid(obj_id)
  176. def get_object_display(self, datum):
  177. return datum.ip
  178. class Meta(object):
  179. name = "floating_ips"
  180. verbose_name = _("Floating IPs")
  181. table_actions = (AllocateIP, ReleaseIPs)
  182. row_actions = (AssociateIP, DisassociateIP, ReleaseIPs)