Commit fda9c192 by Szabolcs Gelencser

implement network create, details

parent 327e7892
No preview for this file type
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="list-group" id="vxlan-list-view"> <div class="list-group" id="vxlan-list-view">
<div id="dashboard-vxlan-list"> <div id="dashboard-vxlan-list">
{% for vxlan in vxlans %} {% for vxlan in vxlans %}
<a href="{% url "network.vxlan" vni=vxlan.vni %}" class="list-group-item <a href="{% url "network.vxlan" pk=vxlan.id %}" class="list-group-item
{% if forloop.last and vxlan|length < 5 %} list-group-item-last{% endif %}"> {% if forloop.last and vxlan|length < 5 %} list-group-item-last{% endif %}">
<span class="index-vxlan-list-name"> <span class="index-vxlan-list-name">
<i class="fa fa-sitemap"></i> {{ vxlan.name }} <i class="fa fa-sitemap"></i> {{ vxlan.name }}
......
...@@ -106,7 +106,7 @@ class IndexView(LoginRequiredMixin, TemplateView): ...@@ -106,7 +106,7 @@ class IndexView(LoginRequiredMixin, TemplateView):
'operator', user, disregard_superuser=True).all()[:5] 'operator', user, disregard_superuser=True).all()[:5]
# vxlan # vxlan
#context['vxlans'] = Instance.list_from_os(self.request)[:5] context['vxlans'] = Vxlan.list_from_os(self.request)[:5]
# toplist # toplist
if settings.STORE_URL: if settings.STORE_URL:
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.forms import ModelForm, widgets from django.forms import ModelForm, widgets
from django import forms
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -28,6 +29,7 @@ from firewall.models import ( ...@@ -28,6 +29,7 @@ from firewall.models import (
SwitchPort, Firewall SwitchPort, Firewall
) )
from network.models import Vxlan from network.models import Vxlan
from openstack_api.neutron import Network
class LinkButton(BaseInput): class LinkButton(BaseInput):
...@@ -372,21 +374,9 @@ class VxlanSuperUserForm(ModelForm): ...@@ -372,21 +374,9 @@ class VxlanSuperUserForm(ModelForm):
) )
) )
class VxlanForm(ModelForm): class VxlanForm(forms.Form):
helper = FormHelper() name = forms.CharField(widget=forms.TextInput(attrs={
helper.layout = Layout( 'class': "form-control",
Div( 'required': "",
Fieldset( }))
'',
'name',
'description',
'comment',
Field('vni', type='hidden'),
)
),
FormActions(
Submit('submit', _('Save')),
LinkButton('back', _('Back'), reverse_lazy(
'network.vxlan-list'))
)
)
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# #
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import openstack_api
from django.db import models from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -68,6 +68,10 @@ class Vxlan(models.Model): ...@@ -68,6 +68,10 @@ class Vxlan(models.Model):
class Meta: class Meta:
app_label = 'network' app_label = 'network'
@classmethod
def list_from_os(cls, request):
return openstack_api.neutron.network_list_for_tenant(request, request.user.tenant_id)
def __unicode__(self): def __unicode__(self):
return self.name return self.name
......
...@@ -5,18 +5,20 @@ ...@@ -5,18 +5,20 @@
{% load staticfiles %} {% load staticfiles %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block title-page %}{% trans "Create" %} | {% trans "vxlan" %}{% endblock %} {% block title-page %}{% trans "Create" %} | {% trans "network" %}{% endblock %}
{% block content %} {% block content %}
<div class="page-header"> <div class="page-header">
<h2>{% trans "Create a new vxlan" %}</h2> <h2>{% trans "Create a new network" %}</h2>
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-8"> <form method="POST"">
{% crispy form %} {% csrf_token %}
</div> {{ form.name|as_crispy_field }}
<div class="col-sm-4"> <button class="btn btn-success pull-right text-right" type="submit">
</div> <i class="fa fa-plus"></i> {% trans "Create" %}
</button>
</form>
</div> </div>
{% endblock %} {% endblock %}
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
{% block content %} {% block content %}
<div class="page-header"> <div class="page-header">
<a href="{% url "network.vxlan-delete" vni=vxlan.vni %}" class="btn btn-danger pull-right"><i class="fa fa-times-circle"></i> {% trans "Delete this vxlan" %}</a> <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>
<h2>{{ form.name.value }} <small>{% trans "details of vxlan" %}</small></h2> <h2>{{ form.name.value }} <small>{% trans "details of network" %}</small></h2>
</div> </div>
<div class="row"> <div class="row">
...@@ -21,12 +21,7 @@ ...@@ -21,12 +21,7 @@
<div class="page-header"> <div class="page-header">
<h3>{% trans "Connected virtual machines" %}</h3> <h3>{% trans "Connected virtual machines" %}</h3>
</div> </div>
{% render_table vm_list %} {# {% render_table vm_list %}#}
<div class="page-header">
<h3>{% trans "Manage access" %}</h3>
</div>
{% include "dashboard/_manage_access.html" with table_id="vxlan-access-table" %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
...@@ -129,10 +129,11 @@ urlpatterns = [ ...@@ -129,10 +129,11 @@ urlpatterns = [
# vxlan # vxlan
url('^vxlans/$', VxlanList.as_view(), name='network.vxlan-list'), url('^vxlans/$', VxlanList.as_view(), name='network.vxlan-list'),
url('^vxlans/create$', VxlanCreate.as_view(), name='network.vxlan-create'), url('^vxlans/create$', VxlanCreate.as_view(), name='network.vxlan-create'),
url('^vxlans/(?P<vni>\d+)/$', VxlanDetail.as_view(), name='network.vxlan'), url('^vxlans/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/$',
VxlanDetail.as_view(), name='network.vxlan'),
url('^vxlans/(?P<pk>\d+)/acl/$', VxlanAclUpdateView.as_view(), url('^vxlans/(?P<pk>\d+)/acl/$', VxlanAclUpdateView.as_view(),
name='network.vxlan-acl'), name='network.vxlan-acl'),
url('^vxlans/delete/(?P<vni>\d+)/$', VxlanDelete.as_view(), url('^vxlans/delete/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/$', VxlanDelete.as_view(),
name="network.vxlan-delete"), name="network.vxlan-delete"),
# editor # editor
......
...@@ -20,10 +20,11 @@ import random ...@@ -20,10 +20,11 @@ import random
import json import json
from collections import OrderedDict from collections import OrderedDict
import openstack_api
from netaddr import IPNetwork from netaddr import IPNetwork
from django.views.generic import ( from django.views.generic import (
TemplateView, UpdateView, DeleteView, CreateView, TemplateView, UpdateView, DeleteView, CreateView,
) DetailView)
from django.core.exceptions import ( from django.core.exceptions import (
ValidationError, PermissionDenied, ImproperlyConfigured ValidationError, PermissionDenied, ImproperlyConfigured
) )
...@@ -40,6 +41,8 @@ from firewall.models import ( ...@@ -40,6 +41,8 @@ from firewall.models import (
SwitchPort, EthernetDevice, Firewall SwitchPort, EthernetDevice, Firewall
) )
from network.models import Vxlan, EditorElement from network.models import Vxlan, EditorElement
from numpy.distutils.from_template import template_name_re
from openstack_api.neutron import Network
from vm.models import Interface, Instance from vm.models import Interface, Instance
from common.views import CreateLimitedResourceMixin from common.views import CreateLimitedResourceMixin
from .tables import ( from .tables import (
...@@ -50,9 +53,7 @@ from .tables import ( ...@@ -50,9 +53,7 @@ from .tables import (
) )
from .forms import ( from .forms import (
HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm, HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm,
RuleForm, VlanGroupForm, SwitchPortForm, FirewallForm, RuleForm, VlanGroupForm, SwitchPortForm, FirewallForm, VxlanForm)
VxlanForm, VxlanSuperUserForm,
)
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
...@@ -61,7 +62,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -61,7 +62,7 @@ from django.utils.translation import ugettext_lazy as _
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from operator import itemgetter from operator import itemgetter
from itertools import chain from itertools import chain
from dashboard.views import AclUpdateView from dashboard.views import AclUpdateView, FormView
from dashboard.forms import AclUserOrGroupAddForm from dashboard.forms import AclUserOrGroupAddForm
try: try:
...@@ -94,14 +95,6 @@ class MagicMixin(object): ...@@ -94,14 +95,6 @@ class MagicMixin(object):
else: else:
return super(MagicMixin, self).get(*args, **kwargs) return super(MagicMixin, self).get(*args, **kwargs)
class InitialOwnerMixin(FormMixin):
def get_initial(self):
initial = super(InitialOwnerMixin, self).get_initial()
initial['owner'] = self.request.user
return initial
class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView): class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
template_name = "network/index.html" template_name = "network/index.html"
...@@ -225,7 +218,7 @@ class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -225,7 +218,7 @@ class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin, class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = Domain model = Domain
template_name = "network/domain-create.html" template_name = "network/domain-create.html"
form_class = DomainForm form_class = DomainForm
...@@ -356,7 +349,7 @@ class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): ...@@ -356,7 +349,7 @@ class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin, class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = Group model = Group
template_name = "network/group-create.html" template_name = "network/group-create.html"
form_class = GroupForm form_class = GroupForm
...@@ -621,7 +614,7 @@ class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -621,7 +614,7 @@ class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin, class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = Record model = Record
template_name = "network/record-create.html" template_name = "network/record-create.html"
form_class = RecordForm form_class = RecordForm
...@@ -708,7 +701,7 @@ class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -708,7 +701,7 @@ class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin, class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = Rule model = Rule
template_name = "network/rule-create.html" template_name = "network/rule-create.html"
form_class = RuleForm form_class = RuleForm
...@@ -743,6 +736,22 @@ class SwitchPortList(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -743,6 +736,22 @@ class SwitchPortList(LoginRequiredMixin, SuperuserRequiredMixin,
table_pagination = False table_pagination = False
class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, CreateView):
model = Rule
template_name = "network/rule-create.html"
form_class = RuleForm
success_message = _(u'Successfully created rule.')
def get_initial(self):
initial = super(RuleCreate, self).get_initial()
initial.update({
'host': self.request.GET.get('host'),
'hostgroup': self.request.GET.get('hostgroup')
})
return initial
class SwitchPortDetail(LoginRequiredMixin, SuperuserRequiredMixin, class SwitchPortDetail(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, UpdateView): SuccessMessageMixin, UpdateView):
model = SwitchPort model = SwitchPort
...@@ -829,7 +838,7 @@ class VlanDetail(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -829,7 +838,7 @@ class VlanDetail(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
class VlanCreate(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, class VlanCreate(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = Vlan model = Vlan
template_name = "network/vlan-create.html" template_name = "network/vlan-create.html"
form_class = VlanForm form_class = VlanForm
...@@ -909,7 +918,7 @@ class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -909,7 +918,7 @@ class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin,
class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin, class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
SuccessMessageMixin, InitialOwnerMixin, CreateView): SuccessMessageMixin, CreateView):
model = VlanGroup model = VlanGroup
template_name = "network/vlan-group-create.html" template_name = "network/vlan-group-create.html"
form_class = VlanGroupForm form_class = VlanGroupForm
...@@ -963,107 +972,29 @@ class VxlanAclUpdateView(AclUpdateView): ...@@ -963,107 +972,29 @@ class VxlanAclUpdateView(AclUpdateView):
model = Vxlan model = Vxlan
class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView): #TODO: check user class VxlanDetail(LoginRequiredMixin, SuccessMessageMixin, DetailView): #TODO: check user
model = Vxlan # model = Network
slug_field = 'vni'
slug_url_kwarg = 'vni'
success_message = _(u'Succesfully modified vlan %(name)s.') success_message = _(u'Succesfully modified vlan %(name)s.')
success_url = reverse_lazy('network.vxlan-list') success_url = reverse_lazy('network.vxlan-list')
template_name = 'network/vxlan-edit.html'
context_object_name = 'network'
def get_template_names(self): def get_object(self, queryset=None):
if self.request.user.is_superuser: return openstack_api.neutron.network_get(self.request, self.kwargs['pk'])
return ["network/vxlan-superuser-edit.html"]
else:
return ["network/vxlan-edit.html"]
def get_form_class(self, is_post=False):
if self.request.user.is_superuser:
return VxlanSuperUserForm
return VxlanForm
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)
context['vm_list'] = SmallVmTable(self.object.vm_interface.all()) context['vm_list'] = () #SmallVmTable(self.object.vm_interface.all())
context['acl'] = AclUpdateView.get_acl_data( context['form'] = VxlanForm
self.object, self.request.user, 'network.vxlan-acl')
context['aclform'] = AclUserOrGroupAddForm()
return context return context
def post(self, *args, **kwargs): class VxlanCreate(LoginRequiredMixin, FormView):
if not self.object.has_level(self.request.user, 'owner'): form_class = VxlanForm
raise PermissionDenied() template_name = 'network/vxlan-create.html'
return super(VxlanDetail, self).post(*args, **kwargs)
class VxlanCreate(LoginRequiredMixin, SuccessMessageMixin, InitialOwnerMixin, CreateView):
model = Vxlan
profile_attribute = 'network_limit'
resource_name = _('Virtual network')
success_message = _(u'Successfully created vxlan %(name)s.')
def get_template_names(self):
if self.request.user.is_superuser:
return ["network/vxlan-superuser-create.html"]
else:
return ["network/vxlan-create.html"]
def get_form_class(self, is_post=False):
if self.request.user.is_superuser:
return VxlanSuperUserForm
return VxlanForm
def get_initial(self):
initial = super(VxlanCreate, self).get_initial()
initial['vni'] = self._generate_vni()
return initial
def get_default_vlan(self):
vlan = Vlan.objects.filter(
name=settings.DEFAULT_USERNET_VLAN_NAME).first()
if vlan is None:
msg = (_('Cannot find server vlan: %s') %
settings.DEFAULT_USERNET_VLAN_NAME)
if self.request.user.is_superuser:
messages.error(self.request, msg)
logger.error(msg)
raise ImproperlyConfigured()
return vlan
def form_valid(self, form): def form_valid(self, form):
obj = form.save(commit=False) network_created = openstack_api.neutron.network_create(self.request, name=form.cleaned_data['name'])
obj.vlan = self.get_default_vlan() return redirect(reverse_lazy('network.vxlan', kwargs={'pk': network_created.id}))
try:
obj.full_clean()
obj.save()
obj.set_level(obj.owner, 'owner')
self.object = obj
except Exception as e:
msg = _('Unexpected error occured. '
'Please try again or contact administrator!')
messages.error(self.request, msg)
logger.exception(e)
return redirect(self.get_success_url())
def form_invalid(self, form):
# When multiple client get same VNI value
if 'vni' in form.errors.as_data():
messages.error(self.request, _('Cannot create virtual network.'
' Please try again.'))
return redirect('network.vxlan-create')
return super(VxlanCreate, self).form_invalid(form)
def _generate_vni(self):
if Vxlan.objects.count() == settings.USERNET_MAX:
msg = _('Cannot find unused VNI value. '
'Please contact administrator!')
messages.error(self.request, msg)
logger.error(msg)
else:
full_range = set(range(0, settings.USERNET_MAX))
used_values = {vni[0] for vni in Vxlan.objects.values_list('vni')}
free_values = full_range - used_values
return random.choice(list(free_values))
class VxlanDelete(LoginRequiredMixin, DeleteView): #TODO: check user class VxlanDelete(LoginRequiredMixin, DeleteView): #TODO: check user
model = Vlan model = Vlan
......
...@@ -508,7 +508,7 @@ def keypair_get(request, name): ...@@ -508,7 +508,7 @@ def keypair_get(request, name):
def server_create(request, name, image, flavor, key_name=None, user_data=None, def server_create(request, name, image, flavor, key_name=None, user_data=None,
security_groups=None, block_device_mapping=None, security_groups=None, block_device_mapping=None,
block_device_mapping_v2=None, nics="auto", block_device_mapping_v2=None, nics="none",
availability_zone=None, instance_count=1, admin_pass=None, availability_zone=None, instance_count=1, admin_pass=None,
disk_config=None, config_drive=None, meta=None, disk_config=None, config_drive=None, meta=None,
scheduler_hints=None, description=None): scheduler_hints=None, description=None):
......
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