Commit 002facdf by Szeberényi Imre

Merge branch 'template_instance_limit' into 'master'

Template instance limit

See merge request !418
parents 9e18bdbf 729d6f82
Pipeline #1361 passed with stage
in 0 seconds
......@@ -1336,6 +1336,9 @@ class UserEditForm(forms.ModelForm):
instance_limit = forms.IntegerField(
label=_('Instance limit'),
min_value=0, widget=NumberInput)
template_instance_limit = forms.IntegerField(
label=_('Template instance limit'),
min_value=0, widget=NumberInput)
two_factor_secret = forms.CharField(
label=_('Two-factor authentication secret'),
help_text=_("Remove the secret key to disable two-factor "
......@@ -1345,18 +1348,23 @@ class UserEditForm(forms.ModelForm):
super(UserEditForm, self).__init__(*args, **kwargs)
self.fields["instance_limit"].initial = (
self.instance.profile.instance_limit)
self.fields["template_instance_limit"].initial = (
self.instance.profile.template_instance_limit)
self.fields["two_factor_secret"].initial = (
self.instance.profile.two_factor_secret)
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'instance_limit',
'is_active', "two_factor_secret",)
fields = ('email', 'first_name', 'last_name',
'instance_limit', 'template_instance_limit',
'is_active', 'two_factor_secret',)
def save(self, commit=True):
user = super(UserEditForm, self).save()
user.profile.instance_limit = (
self.cleaned_data['instance_limit'] or None)
user.profile.template_instance_limit = (
self.cleaned_data['template_instance_limit'] or None)
user.profile.two_factor_secret = (
self.cleaned_data['two_factor_secret'] or None)
user.profile.save()
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.25 on 2020-11-06 13:33
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dashboard', '0007_groupprofile_disk_quota'),
]
operations = [
migrations.AddField(
model_name='profile',
name='template_instance_limit',
field=models.IntegerField(default=1),
),
]
......@@ -178,6 +178,7 @@ class Profile(Model):
unique=True, blank=True, null=True, max_length=64,
help_text=_('Unique identifier of the person, e.g. a student number.'))
instance_limit = IntegerField(default=5)
template_instance_limit = IntegerField(default=1)
use_gravatar = BooleanField(
verbose_name=_("Use Gravatar"), default=True,
help_text=_("Whether to use email address as Gravatar profile image"))
......
......@@ -534,7 +534,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
with patch.object(DeployOperation, 'async') as async:
response = c.post("/dashboard/vm/create/", {
'name': 'vm',
'amount': 2,
'amount': 1,
'customized': 1,
'template': 1,
'cpu_priority': 10, 'cpu_count': 1, 'ram_size': 128,
......@@ -543,7 +543,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
assert async.called
self.assertEqual(response.status_code, 302)
self.assertEqual(instance_count + 2, Instance.objects.all().count())
self.assertEqual(instance_count + 1, Instance.objects.all().count())
def test_unpermitted_description_update(self):
c = Client()
......
......@@ -460,8 +460,7 @@ class VmMigrateView(FormOperationMixin, VmOperationView):
if isinstance(inst, Instance):
nodes_w_traits = [
n.pk for n in Node.objects.filter(enabled=True)
if n.online and
has_traits(inst.req_traits.all(), n)
if n.online and has_traits(inst.req_traits.all(), n)
]
ctx['nodes_w_traits'] = nodes_w_traits
......@@ -1166,24 +1165,28 @@ class VmCreate(LoginRequiredMixin, TemplateView):
# limit chekcs
try:
limit = user.profile.instance_limit
instance_limit = user.profile.instance_limit
template_instance_limit = user.profile.template_instance_limit
except Exception as e:
logger.debug('No profile or instance limit: %s', e)
else:
try:
amount = int(request.POST.get("amount", 1))
except:
amount = limit # TODO this should definitely use a Form
current = Instance.active.filter(owner=user).count()
logger.debug('current use: %d, limit: %d', current, limit)
if current + amount > limit:
messages.error(request,
_('Instance limit (%d) exceeded.') % limit)
if request.is_ajax():
return HttpResponse(json.dumps({'redirect': '/'}),
content_type="application/json")
else:
return redirect('/')
# TODO this should definitely use a Form
amount = instance_limit
instances = Instance.active.filter(owner=user).count()
template_instances = template.get_user_instances(user).count()
logger.debug('current instance use: %d, limit: %d',
instances, instance_limit)
logger.debug('current template instance use: %d, limit: %d',
template_instances, template_instance_limit)
if instances + amount > instance_limit:
return self._limit_exceeded(instance_limit, request)
if template_instances + amount > template_instance_limit:
return self._limit_exceeded(template_instance_limit, request)
create_func = (self.__create_normal if
request.POST.get("customized") is None else
......@@ -1191,6 +1194,16 @@ class VmCreate(LoginRequiredMixin, TemplateView):
return create_func(request, template, *args, **kwargs)
def _limit_exceeded(self, limit, request):
messages.error(request,
_('Instance limit (%d) exceeded.')
% limit)
if request.is_ajax():
return HttpResponse(json.dumps({'redirect': '/'}),
content_type="application/json")
else:
return redirect('/')
@require_GET
def get_vm_screenshot(request, pk):
......
......@@ -200,6 +200,9 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
def get_running_instances(self):
return Instance.active.filter(template=self, status="RUNNING")
def get_user_instances(self, user):
return Instance.active.filter(template=self, owner=user)
@property
def metric_prefix(self):
return 'template.%d' % self.pk
......
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