diff --git a/circle/dashboard/fixtures/test-vm-fixture.json b/circle/dashboard/fixtures/test-vm-fixture.json index f008311..6042a51 100644 --- a/circle/dashboard/fixtures/test-vm-fixture.json +++ b/circle/dashboard/fixtures/test-vm-fixture.json @@ -1404,5 +1404,71 @@ "network_type": "public", "description": "" } +}, +{ + "pk": 1, + "model": "firewall.vlan", + "fields": { + "comment": "", + "domain": 1, + "dhcp_pool": "", + "managed": true, + "name": "pub", + "vid": 1066, + "created_at": "2014-01-23T16:51:58.125Z", + "modified_at": "2014-01-23T16:51:58.125Z", + "owner": null, + "snat_ip": null, + "snat_to": [], + "network6": null, + "network4": "152.66.254.61/30", + "reverse_domain": "%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa", + "network_type": "public", + "description": "" + } +}, +{ + "pk": 1, + "model": "vm.lease", + "fields": { + "suspend_interval_seconds": 36000, + "name": "alap", + "delete_interval_seconds": 360000 + } +}, +{ + "pk": 2, + "model": "vm.interfacetemplate", + "fields": { + "vlan": 1, + "managed": true, + "template": 1 + } +}, +{ + "pk": 1, + "model": "vm.instancetemplate", + "fields": { + "req_traits": [], + "disks": [ + 1 + ], + "name": "ubuntu", + "parent": null, + "created": "2014-01-23T18:03:52.319Z", + "num_cores": 2, + "description": "", + "boot_menu": false, + "ram_size": 1024, + "modified": "2014-01-24T00:58:19.654Z", + "system": "", + "priority": 20, + "state": "READY", + "access_method": "ssh", + "raw_data": "", + "arch": "x86_64", + "max_ram_size": 1024, + "lease": 1 + } } ] diff --git a/circle/dashboard/forms.py b/circle/dashboard/forms.py index ac01529..d850c8d 100644 --- a/circle/dashboard/forms.py +++ b/circle/dashboard/forms.py @@ -32,9 +32,7 @@ class VmCreateForm(forms.Form): required=False ) - managed_networks = forms.ModelMultipleChoiceField( - queryset=VLANS, required=False) - unmanaged_networks = forms.ModelMultipleChoiceField( + networks = forms.ModelMultipleChoiceField( queryset=VLANS, required=False) def __init__(self, *args, **kwargs): @@ -208,24 +206,11 @@ class VmCreateForm(forms.Form): ), Div( Div( # js-hidden - AnyTag( - "h4", - HTML(_("Managed networks")), - ), Field( - "managed_networks", + "networks", css_class="form-control", id="vm-create-network-add-managed", ), - AnyTag( - "h4", - HTML(_("Unmanaged networks")), - ), - Field( - "unmanaged_networks", - css_class="form-control", - id="vm-create-network-add-unmanaged", - ), css_class="js-hidden", style="padding-top: 15px; max-width: 450px;", ), @@ -243,24 +228,6 @@ class VmCreateForm(forms.Form): css_class="form-control", css_id="vm-create-network-add-select", ), - AnyTag( - "span", - WorkingBaseInput( - "", - "", - css_id=( - "vm-create-network-add" - "-checkbox-managed" - ), - input_type="checkbox", - title="", - data_original_title=( - _("Managed network?") - ), - checked="checked", - ), - css_class="input-group-addon", - ), Div( AnyTag( "a", @@ -455,9 +422,7 @@ class NodeForm(forms.ModelForm): class TemplateForm(forms.ModelForm): - managed_networks = forms.ModelMultipleChoiceField( - queryset=VLANS, required=False) - unmanaged_networks = forms.ModelMultipleChoiceField( + networks = forms.ModelMultipleChoiceField( queryset=VLANS, required=False) def __init__(self, *args, **kwargs): @@ -482,12 +447,8 @@ class TemplateForm(forms.ModelForm): self.for_networks = self.instance if self.instance.pk or parent is not None: - mn = self.for_networks.interface_set.filter( - managed=True).values_list("vlan", flat=True) - un = self.for_networks.interface_set.filter( - managed=False).values_list("vlan", flat=True) - self.initial['managed_networks'] = mn - self.initial['unmanaged_networks'] = un + n = self.for_networks.interface_set.values_list("vlan", flat=True) + self.initial['networks'] = n if not self.instance.pk and len(self.errors) < 1: self.instance.priority = 20 @@ -505,27 +466,16 @@ class TemplateForm(forms.ModelForm): self.instance.disks = data['disks'] # TODO why do I need this # create and/or delete InterfaceTemplates - managed = InterfaceTemplate.objects.filter( - managed=True, template=self.instance).values_list("vlan", - flat=True) - unmanaged = InterfaceTemplate.objects.filter( - managed=False, template=self.instance).values_list("vlan", - flat=True) - for m in data['managed_networks']: - if m.pk not in managed: - InterfaceTemplate(vlan=m, managed=True, + networks = InterfaceTemplate.objects.filter( + template=self.instance).values_list("vlan", flat=True) + for m in data['networks']: + if m.pk not in networks: + InterfaceTemplate(vlan=m, managed=m.managed, template=self.instance).save() InterfaceTemplate.objects.filter( - managed=True, template=self.instance).exclude( - vlan__in=data['managed_networks']).delete() + template=self.instance).exclude( + vlan__in=data['networks']).delete() - for u in data['unmanaged_networks']: - if u.pk not in unmanaged: - InterfaceTemplate(vlan=u, managed=False, - template=self.instance).save() - InterfaceTemplate.objects.filter( - managed=False, template=self.instance).exclude( - vlan__in=data['unmanaged_networks']).delete() return instance @property @@ -591,8 +541,7 @@ class TemplateForm(forms.ModelForm): Fieldset( _("Exeternal"), Field("disks"), - Field("managed_networks"), - Field("unmanaged_networks"), + Field("networks"), Field("lease"), Field("tags"), ), diff --git a/circle/dashboard/templates/dashboard/vm-detail/network.html b/circle/dashboard/templates/dashboard/vm-detail/network.html index 83c67ad..8c6b05e 100644 --- a/circle/dashboard/templates/dashboard/vm-detail/network.html +++ b/circle/dashboard/templates/dashboard/vm-detail/network.html @@ -125,9 +125,6 @@ <option value="{{ v.pk }}">{{ v.name }}</option> {% endfor %} </select> - <span class="input-group-addon"> - <input type="checkbox" name="new_network_managed" checked="checked" title="{% trans "Managed network?" %}"> - </span> <div class="input-group-btn"> <button type="submit" class="btn btn-success"><i class="icon-plus-sign"></i></button> </div> diff --git a/circle/dashboard/tests/test_views.py b/circle/dashboard/tests/test_views.py index df1da94..b5b84a2 100644 --- a/circle/dashboard/tests/test_views.py +++ b/circle/dashboard/tests/test_views.py @@ -132,3 +132,12 @@ class VmDetailTest(TestCase): {'new_network_vlan': 1, 'managed': 'on'}) self.assertEqual(response.status_code, 302) self.assertEqual(inst.interface_set.count(), interface_count + 1) + + def test_create_vm_w_unpermitted_network(self): + c = Client() + self.login(c, 'user1') + response = c.post('/dashboard/vm/create/', + {'template': 1, + 'cpu_priority': 1, 'cpu_count': 1, + 'ram_size': 1000}) + self.assertEqual(response.status_code, 403) diff --git a/circle/dashboard/views.py b/circle/dashboard/views.py index 0b4a96b..3701601 100644 --- a/circle/dashboard/views.py +++ b/circle/dashboard/views.py @@ -141,7 +141,8 @@ class VmDetailView(CheckedDetailView): ).order_by('-started').select_related() context['activity'] = ia - context['vlans'] = Vlan.objects.all() # TODO acl + context['vlans'] = Vlan.get_objects_with_level( + 'user', self.request.user).all() context['acl'] = get_acl_data(instance) return context @@ -297,11 +298,11 @@ class VmDetailView(CheckedDetailView): raise PermissionDenied() vlan = Vlan.objects.get(pk=request.POST.get("new_network_vlan")) - managed = request.POST.get("new_network_managed") - managed = False if managed is None else True + if not vlan.has_level(request.user, 'user'): + raise PermissionDenied() try: Interface.create(vlan=vlan, instance=self.object, - managed=managed, owner=request.user) + managed=vlan.managed, owner=request.user) messages.success(request, _("Successfully added new interface!")) except Exception, e: error = u' '.join(e.messages) @@ -544,13 +545,13 @@ class VmCreate(LoginRequiredMixin, TemplateView): def get(self, request, form=None, *args, **kwargs): if form is None: form = self.form_class() + form.fields['disks'].queryset = Disk.objects.all() + form.fields['networks'].queryset = Vlan.get_objects_with_level( + 'user', request.user) context = self.get_context_data(**kwargs) context.update({ 'template': 'dashboard/vm-create.html', 'box_title': 'Create a VM', - 'templates': InstanceTemplate.objects.all(), - 'vlans': Vlan.objects.all(), - 'disks': Disk.objects.exclude(type="qcow2-snap"), 'vm_create_form': form, }) return self.render_to_response(context) @@ -578,12 +579,8 @@ class VmCreate(LoginRequiredMixin, TemplateView): 'ram_size': post['ram_size'], 'priority': post['cpu_priority'], } - - networks = ( - [InterfaceTemplate(vlan=l, managed=True) - for l in post['managed_networks']] + - [InterfaceTemplate(vlan=l, managed=False) - for l in post['unmanaged_networks']]) + networks = [InterfaceTemplate(vlan=l, managed=l.managed) + for l in post['networks']] disks = post['disks'] inst = Instance.create_from_template( template=template, owner=user, networks=networks, diff --git a/circle/vm/models/instance.py b/circle/vm/models/instance.py index dcec1fa..410e448 100644 --- a/circle/vm/models/instance.py +++ b/circle/vm/models/instance.py @@ -24,6 +24,7 @@ from .activity import instance_activity from .common import BaseResourceConfigModel, Lease from .network import Interface from .node import Node, Trait +from django.core.exceptions import PermissionDenied logger = getLogger(__name__) pre_state_changed = Signal(providing_args=["new_state"]) @@ -260,6 +261,10 @@ class Instance(AclBase, VirtualMachineDescModel, TimeStampedModel): networks = (template.interface_set.all() if networks is None else networks) + for network in networks: + if not network.vlan.has_level(owner, 'user'): + raise PermissionDenied() + req_traits = (template.req_traits.all() if req_traits is None else req_traits)