Commit 2c453601 by Szabolcs Gelencser

Implement network operations base, delete network operation

parent 27b5943c
...@@ -384,3 +384,10 @@ class VxlanForm(forms.Form): ...@@ -384,3 +384,10 @@ class VxlanForm(forms.Form):
isAdvancedConfig = forms.BooleanField(required=False, label="Advanced") isAdvancedConfig = forms.BooleanField(required=False, label="Advanced")
#TODO: validate #TODO: validate
class NetworkDeleteForm(forms.Form):
@property
def helper(self):
helper = super(NetworkDeleteForm, self).helper
helper.layout = Layout()
return helper
...@@ -30,7 +30,7 @@ from django.contrib.contenttypes.models import ContentType ...@@ -30,7 +30,7 @@ from django.contrib.contenttypes.models import ContentType
from firewall.models import Vlan from firewall.models import Vlan
from firewall.fields import val_alfanum from firewall.fields import val_alfanum
from openstack_auth.user import User from openstack_auth.user import User
from network import operations
class EditorElement(models.Model): class EditorElement(models.Model):
x = models.IntegerField() x = models.IntegerField()
......
import openstack_api
from common.models import humanize_exception
from common.operations import Operation, register_operation
from django.core.exceptions import PermissionDenied
from django.utils.translation import ugettext_noop
from openstack_api.neutron import Network
from django.utils.translation import ugettext_lazy as _
class NetworkOperation(Operation):
host_cls = Network
os_policy_actions = None
def __init__(self, instance):
super(NetworkOperation, self).__init__(subject=instance)
self.instance = instance
def check_precond(self):
pass
def check_auth(self, user, request):
if self.os_policy_actions:
from django.utils.module_loading import import_string
check = import_string("openstack_auth.policy.check")
has_rights = check(self.os_policy_actions, request,
{'project_id': self.instance.tenant_id})
if not has_rights:
raise humanize_exception(ugettext_noop(
"operation not permitted"),
PermissionDenied())
super(NetworkOperation, self).check_auth(user=user)
def is_preferred(self):
"""If this is the recommended op in the current state of the instance.
"""
return False
@register_operation
class DeleteNetworkOperation(NetworkOperation):
id = 'delete_network'
name = _("delete network")
description = _("Delete network and all associated resources.")
os_policy_actions = (
("network", "network:delete"),
)
#TODO: remove attached interfaces, delete ports and assigned floating ips
def _operation(self, request):
ports = openstack_api.neutron.port_list(request, network=self.instance.id)
network_ports = [p for p in ports if p.network_id == self.instance.id]
for p in network_ports:
if p.device_owner == "network:router_interface":
openstack_api.neutron.router_remove_interface(request, p.device_id, port_id=p.id)
if p.device_owner == "compute:nova":
openstack_api.neutron.port_delete(request, p.id)
# openstack_api.neutron.port_delete(request, p.id)
openstack_api.neutron.network_delete(request, self.instance.id)
...@@ -28,8 +28,15 @@ ...@@ -28,8 +28,15 @@
<div class="page-header"> <div class="page-header">
<a href="{% url "network.vxlan-delete" pk=network.id %}" class="btn btn-danger pull-right"><i class="fa fa-times-circle"></i> {% trans "Delete this network" %}</a> {% with op=op.delete_network %}{% if op %}
<h2>{{ form.name.value }}</h2> <span class="operation-wrapper pull-right">
<a href="{% url "network.vxlan-delete" pk=network.id %}"
class="btn btn-{{ op.effect }} operation"
{% if op.disabled %}disabled{% endif %}>{% trans "Delete this network" %}
</a>
</span>
{% endif %}{% endwith %}
<h2>{{ form.name.value }}</h2>
</div> </div>
<div class="row"> <div class="row">
...@@ -41,6 +48,7 @@ ...@@ -41,6 +48,7 @@
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<h3 class="pull-right"><small>{% trans "connected virtual machines" %}</small></h3> <h3 class="pull-right"><small>{% trans "connected virtual machines" %}</small></h3>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -24,7 +24,7 @@ from operator import itemgetter ...@@ -24,7 +24,7 @@ from operator import itemgetter
import openstack_api import openstack_api
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from dashboard.forms import AclUserOrGroupAddForm from dashboard.forms import AclUserOrGroupAddForm
from dashboard.views import AclUpdateView, FormView from dashboard.views import AclUpdateView, FormView, OperationView, PermissionDenied
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import ( from django.core.exceptions import (
...@@ -47,12 +47,13 @@ from firewall.models import ( ...@@ -47,12 +47,13 @@ from firewall.models import (
) )
from netaddr import IPNetwork from netaddr import IPNetwork
from network.models import Vxlan, EditorElement, SubnetPool from network.models import Vxlan, EditorElement, SubnetPool
from openstack_api.neutron import Network
from openstack_api.utils.lazy_encoder import LazyTranslationEncoder from openstack_api.utils.lazy_encoder import LazyTranslationEncoder
from vm.models import Interface, Instance from vm.models import Interface, Instance
from .forms import ( from .forms import (
HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm, HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm,
RuleForm, VlanGroupForm, SwitchPortForm, FirewallForm, VxlanForm) RuleForm, VlanGroupForm, SwitchPortForm, FirewallForm, VxlanForm, NetworkDeleteForm)
from .tables import ( from .tables import (
HostTable, VlanTable, SmallHostTable, DomainTable, GroupTable, HostTable, VlanTable, SmallHostTable, DomainTable, GroupTable,
RecordTable, BlacklistItemTable, RuleTable, VlanGroupTable, RecordTable, BlacklistItemTable, RuleTable, VlanGroupTable,
...@@ -89,6 +90,47 @@ class MagicMixin(object): ...@@ -89,6 +90,47 @@ class MagicMixin(object):
else: else:
return super(MagicMixin, self).get(*args, **kwargs) return super(MagicMixin, self).get(*args, **kwargs)
class VxlanDelete(LoginRequiredMixin, OperationView): #TODO: check user
model = Network
op = 'delete_network'
effect = 'danger'
# form_class = NetworkDeleteForm
def get_success_url(self):
next = self.request.POST.get('next')
if next:
return next
else:
return reverse_lazy('network.vxlan-list')
def get_object(self, queryset=None):
return openstack_api.neutron.network_get(self.request, self.kwargs['pk'], expand_subnet=True)
def delete(self, request, *args, **kwargs):
response = super(VxlanDelete, self).delete(request, *args, **kwargs)
messages.success(request, _(u"Vxlan successfully deleted."))
return response
network_ops = OrderedDict([
('network_delete', VxlanDelete),
])
def get_operations(instance, user, request):
ops = []
for k, v in network_ops.iteritems():
try:
op = v.get_op_by_object(instance)
op.check_auth(user, request)
op.check_precond()
except PermissionDenied as e:
logger.debug('Not showing operation %s for %s: %s',
k, instance, unicode(e))
except Exception as e:
ops.append(v.bind_to_object(instance, disabled=True))
else:
ops.append(v.bind_to_object(instance))
return ops
class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView): class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
template_name = "network/index.html" template_name = "network/index.html"
...@@ -978,6 +1020,7 @@ class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, DetailView): #TODO: c ...@@ -978,6 +1020,7 @@ class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, DetailView): #TODO: c
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(VxlanDetail, self).get_context_data(**kwargs) context = super(VxlanDetail, self).get_context_data(**kwargs)
ops = get_operations(self.object, self.request.user, self.request)
subnet = self.object.subnets[0] if len(self.object.subnets) > 0 else None subnet = self.object.subnets[0] if len(self.object.subnets) > 0 else None
...@@ -991,6 +1034,7 @@ class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, DetailView): #TODO: c ...@@ -991,6 +1034,7 @@ class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, DetailView): #TODO: c
context['isSubnetMissing'] = len(self.object.subnets) < 1 context['isSubnetMissing'] = len(self.object.subnets) < 1
context['vm_list'] = () #SmallVmTable(self.object.vm_interface.all()) context['vm_list'] = () #SmallVmTable(self.object.vm_interface.all())
context['form'] = form context['form'] = form
context['op'] = {i.op: i for i in ops}
return context return context
class VxlanCreate(LoginRequiredMixin, FormView): class VxlanCreate(LoginRequiredMixin, FormView):
...@@ -1023,44 +1067,6 @@ class VxlanCreate(LoginRequiredMixin, FormView): ...@@ -1023,44 +1067,6 @@ class VxlanCreate(LoginRequiredMixin, FormView):
return redirect(reverse_lazy('network.vxlan', kwargs={'pk': network_created.id})) return redirect(reverse_lazy('network.vxlan', kwargs={'pk': network_created.id}))
class VxlanDelete(LoginRequiredMixin, DeleteView): #TODO: check user
model = Vlan
read_level = 'owner'
def get_template_names(self):
if self.request.user.is_superuser:
return ["network/confirm/base_delete.html"]
else:
return ["dashboard/confirm/base-delete.html"]
def get_success_url(self):
next = self.request.POST.get('next')
if next:
return next
else:
return reverse_lazy('network.vxlan-list')
def get_object(self, queryset=None):
""" we identify vlans by vid and not pk """
return Vxlan.objects.get(vni=self.kwargs['vni'])
def delete(self, request, *args, **kwargs):
if self.request.user.is_superuser:
self.object = self.get_object()
if unicode(self.object) != request.POST.get('confirm'):
messages.error(request, _(u"Object name does not match."))
return self.get(request, *args, **kwargs)
response = super(VxlanDelete, self).delete(request, *args, **kwargs)
messages.success(request, _(u"Vxlan successfully deleted."))
return response
def get_context_data(self, **kwargs):
context = super(VxlanDelete, self).get_context_data(**kwargs)
if self.request.user.is_superuser:
context['confirmation'] = True
return context
class TopologyBaseTab(): class TopologyBaseTab():
def get_context_data(request, context=None): def get_context_data(request, context=None):
"""Returns common context data for network topology views.""" """Returns common context data for network topology views."""
......
...@@ -105,6 +105,9 @@ class Agent(NeutronAPIDictWrapper): ...@@ -105,6 +105,9 @@ class Agent(NeutronAPIDictWrapper):
class Network(NeutronAPIDictWrapper): class Network(NeutronAPIDictWrapper):
"""Wrapper for neutron Networks.""" """Wrapper for neutron Networks."""
def __repr__(self):
return self.name
class Subnet(NeutronAPIDictWrapper): class Subnet(NeutronAPIDictWrapper):
"""Wrapper for neutron subnets.""" """Wrapper for neutron subnets."""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment