Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
002facdf
authored
Nov 11, 2020
by
Szeberényi Imre
Browse files
Options
Browse Files
Download
Plain Diff
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
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
63 additions
and
18 deletions
+63
-18
circle/dashboard/forms.py
+10
-2
circle/dashboard/migrations/0008_profile_template_instance_limit.py
+20
-0
circle/dashboard/models.py
+1
-0
circle/dashboard/tests/test_views.py
+2
-2
circle/dashboard/views/vm.py
+27
-14
circle/vm/models/instance.py
+3
-0
No files found.
circle/dashboard/forms.py
View file @
002facdf
...
@@ -1336,6 +1336,9 @@ class UserEditForm(forms.ModelForm):
...
@@ -1336,6 +1336,9 @@ class UserEditForm(forms.ModelForm):
instance_limit
=
forms
.
IntegerField
(
instance_limit
=
forms
.
IntegerField
(
label
=
_
(
'Instance limit'
),
label
=
_
(
'Instance limit'
),
min_value
=
0
,
widget
=
NumberInput
)
min_value
=
0
,
widget
=
NumberInput
)
template_instance_limit
=
forms
.
IntegerField
(
label
=
_
(
'Template instance limit'
),
min_value
=
0
,
widget
=
NumberInput
)
two_factor_secret
=
forms
.
CharField
(
two_factor_secret
=
forms
.
CharField
(
label
=
_
(
'Two-factor authentication secret'
),
label
=
_
(
'Two-factor authentication secret'
),
help_text
=
_
(
"Remove the secret key to disable two-factor "
help_text
=
_
(
"Remove the secret key to disable two-factor "
...
@@ -1345,18 +1348,23 @@ class UserEditForm(forms.ModelForm):
...
@@ -1345,18 +1348,23 @@ class UserEditForm(forms.ModelForm):
super
(
UserEditForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
UserEditForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
fields
[
"instance_limit"
]
.
initial
=
(
self
.
fields
[
"instance_limit"
]
.
initial
=
(
self
.
instance
.
profile
.
instance_limit
)
self
.
instance
.
profile
.
instance_limit
)
self
.
fields
[
"template_instance_limit"
]
.
initial
=
(
self
.
instance
.
profile
.
template_instance_limit
)
self
.
fields
[
"two_factor_secret"
]
.
initial
=
(
self
.
fields
[
"two_factor_secret"
]
.
initial
=
(
self
.
instance
.
profile
.
two_factor_secret
)
self
.
instance
.
profile
.
two_factor_secret
)
class
Meta
:
class
Meta
:
model
=
User
model
=
User
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'instance_limit'
,
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'is_active'
,
"two_factor_secret"
,)
'instance_limit'
,
'template_instance_limit'
,
'is_active'
,
'two_factor_secret'
,)
def
save
(
self
,
commit
=
True
):
def
save
(
self
,
commit
=
True
):
user
=
super
(
UserEditForm
,
self
)
.
save
()
user
=
super
(
UserEditForm
,
self
)
.
save
()
user
.
profile
.
instance_limit
=
(
user
.
profile
.
instance_limit
=
(
self
.
cleaned_data
[
'instance_limit'
]
or
None
)
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
=
(
user
.
profile
.
two_factor_secret
=
(
self
.
cleaned_data
[
'two_factor_secret'
]
or
None
)
self
.
cleaned_data
[
'two_factor_secret'
]
or
None
)
user
.
profile
.
save
()
user
.
profile
.
save
()
...
...
circle/dashboard/migrations/0008_profile_template_instance_limit.py
0 → 100644
View file @
002facdf
# -*- 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
),
),
]
circle/dashboard/models.py
View file @
002facdf
...
@@ -178,6 +178,7 @@ class Profile(Model):
...
@@ -178,6 +178,7 @@ class Profile(Model):
unique
=
True
,
blank
=
True
,
null
=
True
,
max_length
=
64
,
unique
=
True
,
blank
=
True
,
null
=
True
,
max_length
=
64
,
help_text
=
_
(
'Unique identifier of the person, e.g. a student number.'
))
help_text
=
_
(
'Unique identifier of the person, e.g. a student number.'
))
instance_limit
=
IntegerField
(
default
=
5
)
instance_limit
=
IntegerField
(
default
=
5
)
template_instance_limit
=
IntegerField
(
default
=
1
)
use_gravatar
=
BooleanField
(
use_gravatar
=
BooleanField
(
verbose_name
=
_
(
"Use Gravatar"
),
default
=
True
,
verbose_name
=
_
(
"Use Gravatar"
),
default
=
True
,
help_text
=
_
(
"Whether to use email address as Gravatar profile image"
))
help_text
=
_
(
"Whether to use email address as Gravatar profile image"
))
...
...
circle/dashboard/tests/test_views.py
View file @
002facdf
...
@@ -534,7 +534,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
...
@@ -534,7 +534,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
with
patch
.
object
(
DeployOperation
,
'async'
)
as
async
:
with
patch
.
object
(
DeployOperation
,
'async'
)
as
async
:
response
=
c
.
post
(
"/dashboard/vm/create/"
,
{
response
=
c
.
post
(
"/dashboard/vm/create/"
,
{
'name'
:
'vm'
,
'name'
:
'vm'
,
'amount'
:
2
,
'amount'
:
1
,
'customized'
:
1
,
'customized'
:
1
,
'template'
:
1
,
'template'
:
1
,
'cpu_priority'
:
10
,
'cpu_count'
:
1
,
'ram_size'
:
128
,
'cpu_priority'
:
10
,
'cpu_count'
:
1
,
'ram_size'
:
128
,
...
@@ -543,7 +543,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
...
@@ -543,7 +543,7 @@ class VmDetailTest(LoginMixin, MockCeleryMixin, TestCase):
assert
async
.
called
assert
async
.
called
self
.
assertEqual
(
response
.
status_code
,
302
)
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
):
def
test_unpermitted_description_update
(
self
):
c
=
Client
()
c
=
Client
()
...
...
circle/dashboard/views/vm.py
View file @
002facdf
...
@@ -460,8 +460,7 @@ class VmMigrateView(FormOperationMixin, VmOperationView):
...
@@ -460,8 +460,7 @@ class VmMigrateView(FormOperationMixin, VmOperationView):
if
isinstance
(
inst
,
Instance
):
if
isinstance
(
inst
,
Instance
):
nodes_w_traits
=
[
nodes_w_traits
=
[
n
.
pk
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
n
.
pk
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
if
n
.
online
and
if
n
.
online
and
has_traits
(
inst
.
req_traits
.
all
(),
n
)
has_traits
(
inst
.
req_traits
.
all
(),
n
)
]
]
ctx
[
'nodes_w_traits'
]
=
nodes_w_traits
ctx
[
'nodes_w_traits'
]
=
nodes_w_traits
...
@@ -1166,24 +1165,28 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -1166,24 +1165,28 @@ class VmCreate(LoginRequiredMixin, TemplateView):
# limit chekcs
# limit chekcs
try
:
try
:
limit
=
user
.
profile
.
instance_limit
instance_limit
=
user
.
profile
.
instance_limit
template_instance_limit
=
user
.
profile
.
template_instance_limit
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
debug
(
'No profile or instance limit:
%
s'
,
e
)
logger
.
debug
(
'No profile or instance limit:
%
s'
,
e
)
else
:
else
:
try
:
try
:
amount
=
int
(
request
.
POST
.
get
(
"amount"
,
1
))
amount
=
int
(
request
.
POST
.
get
(
"amount"
,
1
))
except
:
except
:
amount
=
limit
# TODO this should definitely use a Form
# TODO this should definitely use a Form
current
=
Instance
.
active
.
filter
(
owner
=
user
)
.
count
()
amount
=
instance_limit
logger
.
debug
(
'current use:
%
d, limit:
%
d'
,
current
,
limit
)
instances
=
Instance
.
active
.
filter
(
owner
=
user
)
.
count
()
if
current
+
amount
>
limit
:
template_instances
=
template
.
get_user_instances
(
user
)
.
count
()
messages
.
error
(
request
,
_
(
'Instance limit (
%
d) exceeded.'
)
%
limit
)
logger
.
debug
(
'current instance use:
%
d, limit:
%
d'
,
if
request
.
is_ajax
():
instances
,
instance_limit
)
return
HttpResponse
(
json
.
dumps
({
'redirect'
:
'/'
}),
logger
.
debug
(
'current template instance use:
%
d, limit:
%
d'
,
content_type
=
"application/json"
)
template_instances
,
template_instance_limit
)
else
:
return
redirect
(
'/'
)
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
create_func
=
(
self
.
__create_normal
if
request
.
POST
.
get
(
"customized"
)
is
None
else
request
.
POST
.
get
(
"customized"
)
is
None
else
...
@@ -1191,6 +1194,16 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -1191,6 +1194,16 @@ class VmCreate(LoginRequiredMixin, TemplateView):
return
create_func
(
request
,
template
,
*
args
,
**
kwargs
)
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
@require_GET
def
get_vm_screenshot
(
request
,
pk
):
def
get_vm_screenshot
(
request
,
pk
):
...
...
circle/vm/models/instance.py
View file @
002facdf
...
@@ -200,6 +200,9 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
...
@@ -200,6 +200,9 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
def
get_running_instances
(
self
):
def
get_running_instances
(
self
):
return
Instance
.
active
.
filter
(
template
=
self
,
status
=
"RUNNING"
)
return
Instance
.
active
.
filter
(
template
=
self
,
status
=
"RUNNING"
)
def
get_user_instances
(
self
,
user
):
return
Instance
.
active
.
filter
(
template
=
self
,
owner
=
user
)
@property
@property
def
metric_prefix
(
self
):
def
metric_prefix
(
self
):
return
'template.
%
d'
%
self
.
pk
return
'template.
%
d'
%
self
.
pk
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment