Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE3
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
5
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
140a1932
authored
Sep 12, 2022
by
Karsa Zoltán István
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add rest endpoints to node, vlan, deploy, shutdown, destroy
parent
60007ab6
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
210 additions
and
14 deletions
+210
-14
circle/dashboard/serializers.py
+26
-5
circle/dashboard/urls.py
+12
-3
circle/dashboard/views/node.py
+35
-0
circle/dashboard/views/template.py
+8
-0
circle/dashboard/views/vm.py
+129
-6
No files found.
circle/dashboard/serializers.py
View file @
140a1932
from
rest_framework.renderers
import
JSONRenderer
from
rest_framework
import
serializers
from
vm.models
import
Instance
,
InstanceTemplate
,
Lease
,
Interface
from
vm.models
import
Instance
,
InstanceTemplate
,
Lease
,
Interface
,
Node
from
firewall.models
import
Vlan
from
storage.models
import
Disk
class
NodeSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Node
fields
=
[
'id'
,
'name'
,
'priority'
,
'host'
,
'enabled'
,
'schedule_enabled'
,
'traits'
,
'overcommit'
,
'ram_weight'
,
'cpu_weight'
,
'time_stamp'
]
class
InstanceTemplateSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
InstanceTemplate
...
...
@@ -42,7 +49,10 @@ class InstanceSerializer(serializers.ModelSerializer):
fields
=
[
'id'
,
'name'
,
'description'
,
'status'
,
'owner'
,
'access_method'
,
'boot_menu'
,
'pw'
,
'is_base'
,
'lease'
,
'raw_data'
,
'cloud_init'
,
'ci_meta_data'
,
'ci_user_data'
,
'system'
,
'req_traits'
,
'has_agent'
,
'num_cores'
,
'ram_size'
,
'max_ram_size'
,
'arch'
,
'priority'
,
'disks'
,
'node'
,
'ipv4addr'
,
'ipv6addr'
]
extra_kwargs
=
{
'disks'
:
{
'required'
:
False
}}
extra_kwargs
=
{
'disks'
:
{
'required'
:
False
,
'allow_empty'
:
True
,},
'req_traits'
:
{
'required'
:
False
,
'allow_empty'
:
True
,}
}
class
InterfaceSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -58,10 +68,21 @@ class VlanSerializer(serializers.ModelSerializer):
class
CreateDiskSerializer
(
serializers
.
Serializer
):
size
=
serializers
.
IntegerField
(
)
size
=
serializers
.
CharField
(
max_length
=
50
)
name
=
serializers
.
CharField
(
max_length
=
100
)
class
ResizeDiskSerializer
(
serializers
.
Serializer
):
size
=
serializers
.
CharField
(
max_length
=
50
)
disk
=
serializers
.
IntegerField
()
class
DownloadDiskSerializer
(
serializers
.
Serializer
):
url
=
serializers
.
CharField
(
max_length
=
500
)
name
=
serializers
.
CharField
(
max_length
=
100
)
\ No newline at end of file
name
=
serializers
.
CharField
(
max_length
=
100
)
class
VMDeploySerializer
(
serializers
.
Serializer
):
node
=
serializers
.
IntegerField
(
required
=
False
)
class
Meta
:
extra_kwargs
=
{
'node'
:
{
'required'
:
False
,
'allow_null'
:
True
}}
\ No newline at end of file
circle/dashboard/urls.py
View file @
140a1932
...
...
@@ -56,19 +56,22 @@ from .views import (
NodeActivityView
,
UserList
,
TemplateREST
,
LeaseREST
,
DiskRest
,
InstanceREST
,
InterfaceREST
,
InstanceFromTemplateREST
,
InstanceFTforUsersREST
,
DownloadDiskREST
,
GetInstanceREST
,
GetInterfaceREST
,
GetLeaseREST
,
GetDiskRest
,
DownloadDiskREST
,
GetInstanceREST
,
GetInterfaceREST
,
ShutdownInstanceREST
,
GetLeaseREST
,
GetDiskRest
,
DeployInstanceREST
,
CreateDiskREST
,
VlanREST
,
ResizeDiskREST
,
GetVlanREST
,
StorageDetail
,
DiskDetail
,
MessageList
,
MessageDetail
,
MessageCreate
,
MessageDelete
,
EnableTwoFactorView
,
DisableTwoFactorView
,
AclUserGroupAutocomplete
,
AclUserAutocomplete
,
RescheduleView
,
GroupImportView
,
GroupExportView
,
)
from
.views.node
import
node_ops
from
.views.node
import
node_ops
,
NodeREST
,
GetNodeREST
from
.views.vm
import
vm_ops
,
vm_mass_ops
urlpatterns
=
[
path
(
'acpi/vm/'
,
InstanceREST
.
as_view
()),
path
(
'acpi/node/'
,
NodeREST
.
as_view
()),
path
(
'acpi/node/<int:pk>/'
,
GetNodeREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/'
,
GetInstanceREST
.
as_view
()),
path
(
'acpi/template/'
,
TemplateREST
.
as_view
()),
path
(
'acpi/ft/'
,
InstanceFromTemplateREST
.
as_view
()),
...
...
@@ -77,9 +80,15 @@ urlpatterns = [
path
(
'acpi/disk/'
,
DiskRest
.
as_view
()),
path
(
'acpi/disk/<int:pk>/'
,
GetDiskRest
.
as_view
()),
path
(
'acpi/interface/'
,
InterfaceREST
.
as_view
()),
path
(
'acpi/vlan/'
,
VlanREST
.
as_view
()),
path
(
'acpi/vlan/<int:pk>/'
,
GetVlanREST
.
as_view
()),
path
(
'acpi/interface/<int:pk>/'
,
GetInterfaceREST
.
as_view
()),
path
(
'acpi/ftusers/'
,
InstanceFTforUsersREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/downloaddisk/'
,
DownloadDiskREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/createdisk/'
,
CreateDiskREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/deploy/'
,
DeployInstanceREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/shutdown/'
,
ShutdownInstanceREST
.
as_view
()),
path
(
'acpi/vm/<int:pk>/resizedisk/'
,
ResizeDiskREST
.
as_view
()),
url
(
r'^$'
,
IndexView
.
as_view
(),
name
=
"dashboard.index"
),
url
(
r"^profile/list/$"
,
UserList
.
as_view
(),
name
=
"dashboard.views.user-list"
),
...
...
circle/dashboard/views/node.py
View file @
140a1932
...
...
@@ -31,6 +31,12 @@ from django.template.loader import render_to_string
from
django.utils.translation
import
ugettext
as
_
from
django.views.generic
import
DetailView
,
TemplateView
,
View
from
rest_framework
import
status
from
rest_framework.views
import
APIView
from
rest_framework.parsers
import
JSONParser
from
rest_framework.authentication
import
TokenAuthentication
,
BasicAuthentication
from
rest_framework.permissions
import
IsAdminUser
from
braces.views
import
LoginRequiredMixin
,
SuperuserRequiredMixin
from
django_tables2
import
SingleTableView
...
...
@@ -45,6 +51,35 @@ from .util import AjaxOperationMixin, OperationView, GraphMixin, DeleteViewBase
from
manager.mancelery
import
crontab_parser
from
dashboard.serializers
import
NodeSerializer
class
NodeREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
get
(
self
,
request
,
format
=
None
):
if
request
.
query_params
.
get
(
'name'
):
try
:
template
=
Node
.
objects
.
filter
(
name__istartswith
=
request
.
query_params
.
get
(
'name'
))
.
get
()
serializer
=
NodeSerializer
(
template
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
except
:
return
JsonResponse
({},
status
=
404
)
templates
=
Node
.
objects
.
all
()
serializer
=
NodeSerializer
(
templates
,
many
=
True
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
class
GetNodeREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
get
(
self
,
request
,
pk
,
format
=
None
):
interface
=
Node
.
objects
.
get
(
pk
=
pk
)
serializer
=
NodeSerializer
(
interface
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
def
get_operations
(
instance
,
user
):
ops
=
[]
...
...
circle/dashboard/views/template.py
View file @
140a1932
...
...
@@ -20,6 +20,7 @@ from datetime import timedelta
import
json
import
logging
from
string
import
Template
from
xml.dom
import
NotFoundErr
from
django.contrib
import
messages
from
django.contrib.auth.models
import
User
...
...
@@ -283,6 +284,13 @@ class LeaseREST(APIView):
permission_classes
=
[
IsAdminUser
]
def
get
(
self
,
request
,
format
=
None
):
if
request
.
query_params
.
get
(
'name'
):
try
:
template
=
Lease
.
objects
.
filter
(
name__istartswith
=
request
.
query_params
.
get
(
'name'
))
.
get
()
serializer
=
LeaseSerializer
(
template
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
except
:
return
JsonResponse
({},
status
=
404
)
templates
=
Lease
.
objects
.
all
()
serializer
=
LeaseSerializer
(
templates
,
many
=
True
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
...
...
circle/dashboard/views/vm.py
View file @
140a1932
...
...
@@ -21,6 +21,7 @@ import logging
from
collections
import
OrderedDict
from
os
import
getenv
from
urllib
import
response
from
xml.dom
import
ValidationErr
from
django.conf
import
settings
from
django.contrib
import
messages
...
...
@@ -43,7 +44,7 @@ from django.views.generic import (
)
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
from
vm.operations
import
D
ownload
DiskOperation
from
vm.operations
import
D
eployOperation
,
DestroyOperation
,
DownloadDiskOperation
,
ShutdownOperation
,
RenewOperation
,
Resize
DiskOperation
from
common.models
import
(
create_readable
,
HumanReadableException
,
fetch_human_exception
,
...
...
@@ -78,6 +79,7 @@ from request.forms import LeaseRequestForm, TemplateRequestForm
from
..models
import
Favourite
,
pwgen
from
manager.scheduler
import
has_traits
import
re
try
:
# Python 2: "unicode" is built-in
...
...
@@ -95,7 +97,36 @@ from rest_framework.parsers import JSONParser
from
rest_framework.authentication
import
TokenAuthentication
,
BasicAuthentication
from
rest_framework.permissions
import
IsAdminUser
from
dashboard.serializers
import
InstanceSerializer
,
InterfaceSerializer
,
CreateDiskSerializer
,
DownloadDiskSerializer
from
dashboard.serializers
import
(
DiskSerializer
,
InstanceSerializer
,
InterfaceSerializer
,
CreateDiskSerializer
,
DownloadDiskSerializer
,
VMDeploySerializer
,
VlanSerializer
,
ResizeDiskSerializer
)
class
VlanREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
get
(
self
,
request
,
format
=
None
):
if
request
.
query_params
.
get
(
'name'
):
try
:
template
=
Vlan
.
objects
.
filter
(
name__istartswith
=
request
.
query_params
.
get
(
'name'
))
.
get
()
serializer
=
VlanSerializer
(
template
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
except
:
return
JsonResponse
({},
status
=
404
)
templates
=
Vlan
.
objects
.
all
()
serializer
=
VlanSerializer
(
templates
,
many
=
True
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
class
GetVlanREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
get
(
self
,
request
,
pk
,
format
=
None
):
interface
=
Vlan
.
objects
.
get
(
pk
=
pk
)
serializer
=
VlanSerializer
(
interface
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
class
InterfaceREST
(
APIView
):
...
...
@@ -150,6 +181,8 @@ class InstanceREST(APIView):
with
inst
.
activity
(
code_suffix
=
'create'
,
readable_name
=
ugettext_noop
(
"create instance (REST)"
),
on_commit
=
__on_commit
,
user
=
inst
.
owner
)
as
act
:
lease
=
Lease
.
objects
.
get
(
pk
=
str
(
data
[
'lease'
]))
RenewOperation
(
inst
)
.
call
(
user
=
request
.
user
,
lease
=
lease
,
force
=
True
,
save
=
True
)
for
net
in
networks
:
Interface
.
create
(
instance
=
inst
,
vlan
=
net
.
vlan
,
owner
=
inst
.
owner
,
managed
=
net
.
managed
,
...
...
@@ -173,6 +206,56 @@ class GetInstanceREST(APIView):
serializer
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
def
post
(
self
,
request
,
pk
,
format
=
None
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
data
=
JSONParser
()
.
parse
(
request
)
deploy
=
VMDeploySerializer
(
data
=
data
)
if
deploy
.
is_valid
():
if
'node'
in
data
:
selected
=
Node
.
objects
.
get
(
pk
=
int
(
data
[
'node'
]))
DeployOperation
(
instance
)
.
call
(
node
=
selected
,
user
=
instance
.
owner
)
else
:
DeployOperation
(
instance
)
.
call
(
node
=
None
,
user
=
instance
.
owner
)
serializer
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
return
JsonResponse
(
deploy
.
errors
,
status
=
400
)
def
delete
(
self
,
request
,
pk
,
format
=
None
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
DestroyOperation
(
instance
)
.
call
(
user
=
instance
.
owner
)
serializer
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
status
=
401
)
class
DeployInstanceREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
post
(
self
,
request
,
pk
,
format
=
None
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
data
=
JSONParser
()
.
parse
(
request
)
deploy
=
VMDeploySerializer
(
data
=
data
)
if
deploy
.
is_valid
():
if
'node'
in
data
:
selected
=
Node
.
objects
.
get
(
pk
=
int
(
data
[
'node'
]))
DeployOperation
(
instance
)
.
call
(
node
=
selected
,
user
=
instance
.
owner
)
else
:
DeployOperation
(
instance
)
.
call
(
node
=
None
,
user
=
instance
.
owner
)
serializer
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
safe
=
False
)
return
JsonResponse
(
deploy
.
errors
,
status
=
400
)
class
ShutdownInstanceREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
post
(
self
,
request
,
pk
,
format
=
None
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
ShutdownOperation
(
instance
)
.
call
(
user
=
instance
.
owner
)
serializer
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
serializer
.
data
,
status
=
400
)
class
DownloadDiskREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
...
...
@@ -186,11 +269,28 @@ class DownloadDiskREST(APIView):
disk_url
=
str
(
data
[
'url'
])
disk_name
=
str
(
data
[
'name'
])
instance
=
Instance
.
objects
.
get
(
pk
=
vm_id
)
old_disks
=
list
(
instance
.
disks
.
all
())
DownloadDiskOperation
(
instance
)
.
_async
(
name
=
disk_name
,
url
=
disk_url
,
user
=
instance
.
owner
)
ret
=
InstanceSerializer
(
instance
,
many
=
False
)
return
JsonResponse
(
ret
.
data
,
status
=
201
)
new_disks
=
instance
.
disks
.
all
()
for
d
in
new_disks
:
if
d
not
in
old_disks
:
ret
=
DiskSerializer
(
d
,
many
=
False
)
return
JsonResponse
(
ret
.
data
,
status
=
201
)
return
JsonResponse
(
serializer
.
errors
,
status
=
400
)
def
size_util
(
size
:
str
):
size_dict
=
{
"GB"
:
1000000000
,
"Gi"
:
1073741824
,
"MB"
:
1000000
,
"Mi"
:
1048576
,
"KB"
:
1000
,
"Ki"
:
1024
,
}
res
=
re
.
search
(
r"(\d*)\s*(\w*)"
,
size
)
if
res
and
res
.
group
(
1
)
and
res
.
group
(
2
):
return
int
(
res
.
group
(
1
))
*
size_dict
[
str
(
res
.
group
(
2
))]
raise
ValidationErr
()
class
CreateDiskREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
...
...
@@ -201,12 +301,35 @@ class CreateDiskREST(APIView):
serializer
=
CreateDiskSerializer
(
data
=
data
)
if
serializer
.
is_valid
():
vm_id
=
pk
disk_size
=
int
(
data
[
'size'
]
)
disk_size
=
str
(
size_util
(
str
(
data
[
'size'
]))
)
disk_name
=
str
(
data
[
'name'
])
instance
=
Instance
.
objects
.
get
(
pk
=
vm_id
)
old_disks
=
list
(
instance
.
disks
.
all
())
instance
.
create_disk
(
size
=
disk_size
,
user
=
instance
.
owner
,
name
=
disk_name
,
activity
=
None
)
ret
=
InstanceSerializer
(
instance
,
many
=
False
)
new_disks
=
instance
.
disks
.
all
()
for
d
in
new_disks
:
if
d
not
in
old_disks
:
ret
=
DiskSerializer
(
d
,
many
=
False
)
return
JsonResponse
(
ret
.
data
,
status
=
201
)
return
JsonResponse
(
serializer
.
errors
,
status
=
400
)
class
ResizeDiskREST
(
APIView
):
authentication_classes
=
[
TokenAuthentication
,
BasicAuthentication
]
permission_classes
=
[
IsAdminUser
]
def
post
(
self
,
request
,
pk
,
format
=
None
):
data
=
JSONParser
()
.
parse
(
request
)
serializer
=
ResizeDiskSerializer
(
data
=
data
)
if
serializer
.
is_valid
():
vm_id
=
pk
disk_size
=
str
(
size_util
(
str
(
data
[
'size'
])))
disk_id
=
str
(
data
[
'disk'
])
instance
=
Instance
.
objects
.
get
(
pk
=
vm_id
)
disk
=
Disk
.
objects
.
get
(
pk
=
disk_id
)
ResizeDiskOperation
(
instance
)
.
call
(
disk
=
disk
,
size
=
disk_size
,
user
=
instance
.
owner
)
ret
=
DiskSerializer
(
disk
,
many
=
False
)
return
JsonResponse
(
ret
.
data
,
status
=
201
)
return
JsonResponse
(
serializer
.
errors
,
status
=
400
)
...
...
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