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
5179872f
authored
Nov 12, 2019
by
Bálint Máhonfai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into export_import_disk
parents
7a8c2ac5
7a49024a
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
54 additions
and
28 deletions
+54
-28
circle/dashboard/models.py
+10
-6
circle/dashboard/store_api.py
+17
-10
circle/dashboard/views/store.py
+7
-1
circle/firewall/tasks/local_tasks.py
+9
-3
circle/manager/mancelery.py
+2
-1
circle/storage/models.py
+3
-3
circle/vm/models/node.py
+1
-1
circle/vm/operations.py
+1
-1
circle/vm/tasks/local_periodic_tasks.py
+4
-2
No files found.
circle/dashboard/models.py
View file @
5179872f
...
@@ -162,7 +162,7 @@ class ConnectCommand(Model):
...
@@ -162,7 +162,7 @@ class ConnectCommand(Model):
validators
=
[
connect_command_template_validator
])
validators
=
[
connect_command_template_validator
])
class
Meta
:
class
Meta
:
ordering
=
(
'id'
,
)
ordering
=
(
'id'
,)
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
self
.
template
return
self
.
template
...
@@ -218,7 +218,7 @@ class Profile(Model):
...
@@ -218,7 +218,7 @@ class Profile(Model):
'id'
:
command
.
id
,
'id'
:
command
.
id
,
'cmd'
:
command
.
template
%
{
'cmd'
:
command
.
template
%
{
'port'
:
instance
.
get_connect_port
(
use_ipv6
=
use_ipv6
),
'port'
:
instance
.
get_connect_port
(
use_ipv6
=
use_ipv6
),
'host'
:
instance
.
get_connect_host
(
use_ipv6
=
use_ipv6
),
'host'
:
instance
.
get_connect_host
(
use_ipv6
=
use_ipv6
),
'password'
:
instance
.
pw
,
'password'
:
instance
.
pw
,
'username'
:
'cloud'
,
'username'
:
'cloud'
,
}}
for
command
in
commands
]
}}
for
command
in
commands
]
...
@@ -263,7 +263,7 @@ class Profile(Model):
...
@@ -263,7 +263,7 @@ class Profile(Model):
super
(
Profile
,
self
)
.
save
(
*
args
,
**
kwargs
)
super
(
Profile
,
self
)
.
save
(
*
args
,
**
kwargs
)
class
Meta
:
class
Meta
:
ordering
=
(
'id'
,
)
ordering
=
(
'id'
,)
permissions
=
(
permissions
=
(
(
'use_autocomplete'
,
_
(
'Can use autocomplete.'
)),
(
'use_autocomplete'
,
_
(
'Can use autocomplete.'
)),
)
)
...
@@ -275,7 +275,7 @@ class FutureMember(Model):
...
@@ -275,7 +275,7 @@ class FutureMember(Model):
group
=
ForeignKey
(
Group
)
group
=
ForeignKey
(
Group
)
class
Meta
:
class
Meta
:
ordering
=
(
'id'
,
)
ordering
=
(
'id'
,)
unique_together
=
(
'org_id'
,
'group'
)
unique_together
=
(
'org_id'
,
'group'
)
def
__unicode__
(
self
):
def
__unicode__
(
self
):
...
@@ -295,7 +295,7 @@ class GroupProfile(AclBase):
...
@@ -295,7 +295,7 @@ class GroupProfile(AclBase):
description
=
TextField
(
blank
=
True
)
description
=
TextField
(
blank
=
True
)
class
Meta
:
class
Meta
:
ordering
=
(
'id'
,
)
ordering
=
(
'id'
,)
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
self
.
group
.
name
return
self
.
group
.
name
...
@@ -331,7 +331,11 @@ def create_profile(user):
...
@@ -331,7 +331,11 @@ def create_profile(user):
profile
,
created
=
Profile
.
objects
.
get_or_create
(
user
=
user
)
profile
,
created
=
Profile
.
objects
.
get_or_create
(
user
=
user
)
try
:
try
:
Store
(
user
)
.
create_user
(
profile
.
smb_password
,
None
,
profile
.
disk_quota
)
store
=
Store
(
user
)
if
store
.
user_exist
():
profile
.
disk_quota
=
store
.
get_quota
()[
'soft'
]
profile
.
save
()
store
.
create_user
(
profile
.
smb_password
,
None
,
profile
.
disk_quota
)
except
:
except
:
logger
.
exception
(
"Can't create user
%
s"
,
unicode
(
user
))
logger
.
exception
(
"Can't create user
%
s"
,
unicode
(
user
))
return
created
return
created
...
...
circle/dashboard/store_api.py
View file @
5179872f
...
@@ -44,9 +44,19 @@ class NoStoreException(StoreApiException):
...
@@ -44,9 +44,19 @@ class NoStoreException(StoreApiException):
pass
pass
class
NoOrgIdException
(
StoreApiException
):
pass
class
Store
(
object
):
class
Store
(
object
):
def
__init__
(
self
,
user
,
default_timeout
=
0.5
):
def
__init__
(
self
,
user
,
default_timeout
=
0.5
):
self
.
store_url
=
settings
.
STORE_URL
if
not
self
.
store_url
:
raise
NoStoreException
if
not
user
.
profile
.
org_id
:
raise
NoOrgIdException
self
.
username
=
'u-
%
s'
%
user
.
profile
.
org_id
self
.
request_args
=
{
'verify'
:
settings
.
STORE_VERIFY_SSL
}
self
.
request_args
=
{
'verify'
:
settings
.
STORE_VERIFY_SSL
}
if
settings
.
STORE_SSL_AUTH
:
if
settings
.
STORE_SSL_AUTH
:
self
.
request_args
[
'cert'
]
=
(
settings
.
STORE_CLIENT_CERT
,
self
.
request_args
[
'cert'
]
=
(
settings
.
STORE_CLIENT_CERT
,
...
@@ -54,18 +64,15 @@ class Store(object):
...
@@ -54,18 +64,15 @@ class Store(object):
if
settings
.
STORE_BASIC_AUTH
:
if
settings
.
STORE_BASIC_AUTH
:
self
.
request_args
[
'auth'
]
=
(
settings
.
STORE_CLIENT_USER
,
self
.
request_args
[
'auth'
]
=
(
settings
.
STORE_CLIENT_USER
,
settings
.
STORE_CLIENT_PASSWORD
)
settings
.
STORE_CLIENT_PASSWORD
)
self
.
username
=
"u-
%
d"
%
user
.
pk
self
.
default_timeout
=
default_timeout
self
.
default_timeout
=
default_timeout
self
.
store_url
=
settings
.
STORE_URL
if
not
self
.
store_url
:
raise
NoStoreException
def
_request
(
self
,
url
,
method
=
get
,
timeout
=
None
,
def
_request
(
self
,
url
,
method
=
get
,
timeout
=
None
,
raise_status_code
=
True
,
**
kwargs
):
raise_status_code
=
True
,
**
kwargs
):
url
=
urljoin
(
self
.
store_url
,
url
)
url
=
urljoin
(
self
.
store_url
,
url
)
if
timeout
is
None
:
if
timeout
is
None
:
timeout
=
self
.
default_timeout
timeout
=
self
.
default_timeout
payload
=
json
.
dumps
(
kwargs
)
if
kwargs
else
None
kwargs
[
'USER'
]
=
self
.
username
payload
=
json
.
dumps
(
kwargs
)
try
:
try
:
headers
=
{
'content-type'
:
'application/json'
}
headers
=
{
'content-type'
:
'application/json'
}
response
=
method
(
url
,
data
=
payload
,
headers
=
headers
,
response
=
method
(
url
,
data
=
payload
,
headers
=
headers
,
...
@@ -83,7 +90,7 @@ class Store(object):
...
@@ -83,7 +90,7 @@ class Store(object):
return
response
return
response
def
_request_cmd
(
self
,
cmd
,
**
kwargs
):
def
_request_cmd
(
self
,
cmd
,
**
kwargs
):
return
self
.
_request
(
self
.
username
,
post
,
CMD
=
cmd
,
**
kwargs
)
return
self
.
_request
(
"/user/"
,
post
,
CMD
=
cmd
,
**
kwargs
)
def
list
(
self
,
path
,
process
=
True
):
def
list
(
self
,
path
,
process
=
True
):
r
=
self
.
_request_cmd
(
"LIST"
,
PATH
=
path
)
r
=
self
.
_request_cmd
(
"LIST"
,
PATH
=
path
)
...
@@ -119,7 +126,7 @@ class Store(object):
...
@@ -119,7 +126,7 @@ class Store(object):
self
.
_request_cmd
(
"RENAME"
,
PATH
=
old_path
,
NEW_NAME
=
new_name
)
self
.
_request_cmd
(
"RENAME"
,
PATH
=
old_path
,
NEW_NAME
=
new_name
)
def
get_quota
(
self
):
# no CMD? :o
def
get_quota
(
self
):
# no CMD? :o
r
=
self
.
_request
(
self
.
username
)
r
=
self
.
_request
(
"/user/"
)
quota
=
r
.
json
()
quota
=
r
.
json
()
quota
.
update
({
quota
.
update
({
'readable_used'
:
filesizeformat
(
float
(
quota
[
'used'
])),
'readable_used'
:
filesizeformat
(
float
(
quota
[
'used'
])),
...
@@ -129,17 +136,17 @@ class Store(object):
...
@@ -129,17 +136,17 @@ class Store(object):
return
quota
return
quota
def
set_quota
(
self
,
quota
):
def
set_quota
(
self
,
quota
):
self
.
_request
(
"/quota/"
+
self
.
username
,
post
,
QUOTA
=
quota
)
self
.
_request
(
"/quota/"
,
post
,
QUOTA
=
quota
)
def
user_exist
(
self
):
def
user_exist
(
self
):
try
:
try
:
self
.
_request
(
self
.
username
)
self
.
_request
(
"/user/"
)
return
True
return
True
except
NotOkException
:
except
NotOkException
:
return
False
return
False
def
create_user
(
self
,
password
,
keys
,
quota
):
def
create_user
(
self
,
password
,
keys
,
quota
):
self
.
_request
(
"/new/"
+
self
.
username
,
method
=
post
,
self
.
_request
(
"/new/"
,
method
=
post
,
SMBPASSWD
=
password
,
KEYS
=
keys
,
QUOTA
=
quota
)
SMBPASSWD
=
password
,
KEYS
=
keys
,
QUOTA
=
quota
)
@staticmethod
@staticmethod
...
...
circle/dashboard/views/store.py
View file @
5179872f
...
@@ -35,7 +35,8 @@ from django.views.generic import TemplateView
...
@@ -35,7 +35,8 @@ from django.views.generic import TemplateView
from
braces.views
import
LoginRequiredMixin
from
braces.views
import
LoginRequiredMixin
from
..store_api
import
Store
,
NoStoreException
,
NotOkException
from
..store_api
import
(
Store
,
NoStoreException
,
NotOkException
,
NoOrgIdException
)
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -70,6 +71,11 @@ class StoreList(LoginRequiredMixin, TemplateView):
...
@@ -70,6 +71,11 @@ class StoreList(LoginRequiredMixin, TemplateView):
return
super
(
StoreList
,
self
)
.
get
(
*
args
,
**
kwargs
)
return
super
(
StoreList
,
self
)
.
get
(
*
args
,
**
kwargs
)
except
NoStoreException
:
except
NoStoreException
:
messages
.
warning
(
self
.
request
,
_
(
"No store."
))
messages
.
warning
(
self
.
request
,
_
(
"No store."
))
except
NoOrgIdException
:
messages
.
warning
(
self
.
request
,
_
(
"Your organization ID is not set."
" To use the store, you need a"
" unique organization ID."
))
except
NotOkException
:
except
NotOkException
:
messages
.
warning
(
self
.
request
,
_
(
"Store has some problems now."
messages
.
warning
(
self
.
request
,
_
(
"Store has some problems now."
" Try again later."
))
" Try again later."
))
...
...
circle/firewall/tasks/local_tasks.py
View file @
5179872f
...
@@ -39,7 +39,7 @@ def _apply_once(name, tasks, queues, task, data):
...
@@ -39,7 +39,7 @@ def _apply_once(name, tasks, queues, task, data):
data
=
data
()
data
=
data
()
for
queue
in
queues
:
for
queue
in
queues
:
try
:
try
:
task
.
apply_async
(
args
=
data
,
queue
=
queue
,
expires
=
60
)
.
get
(
timeout
=
2
)
task
.
apply_async
(
args
=
data
,
queue
=
queue
,
expires
=
60
)
.
get
(
timeout
=
5
)
logger
.
info
(
"
%
s configuration is reloaded. (queue:
%
s)"
,
logger
.
info
(
"
%
s configuration is reloaded. (queue:
%
s)"
,
name
,
queue
)
name
,
queue
)
except
TimeoutError
as
e
:
except
TimeoutError
as
e
:
...
@@ -76,8 +76,14 @@ def reloadtask_worker():
...
@@ -76,8 +76,14 @@ def reloadtask_worker():
logger
.
info
(
"reloadtask_worker: Reload
%
s"
,
", "
.
join
(
tasks
))
logger
.
info
(
"reloadtask_worker: Reload
%
s"
,
", "
.
join
(
tasks
))
firewall_queues
=
get_firewall_queues
()
firewall_queues
=
get_firewall_queues
()
dns_queues
=
[(
"
%
s.dns"
%
i
)
for
i
in
settings
.
get
(
'dns_queues'
,
[
gethostname
()])]
dns_queues
=
settings
.
get
(
'dns_queues'
,
[
gethostname
()])
if
isinstance
(
dns_queues
,
(
str
,
unicode
)):
dns_queues
=
[
dns_queues
]
dns_queues
=
[(
"
%
s.dns"
%
i
)
for
i
in
dns_queues
]
# dns_queues = [("%s.dns" % i) for i in
# settings.get('dns_queues', [gethostname()])]
_apply_once
(
'dns'
,
tasks
,
dns_queues
,
reload_dns
,
_apply_once
(
'dns'
,
tasks
,
dns_queues
,
reload_dns
,
lambda
:
(
dns
(),
))
lambda
:
(
dns
(),
))
...
...
circle/manager/mancelery.py
View file @
5179872f
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
from
celery
import
Celery
from
celery
import
Celery
from
celery.signals
import
worker_ready
from
celery.signals
import
worker_ready
from
datetime
import
timedelta
from
datetime
import
timedelta
from
celery.schedules
import
crontab
from
kombu
import
Queue
,
Exchange
from
kombu
import
Queue
,
Exchange
from
os
import
getenv
from
os
import
getenv
...
@@ -52,7 +53,7 @@ celery.conf.update(
...
@@ -52,7 +53,7 @@ celery.conf.update(
'dashboard.send_email_notifications'
:
{
'dashboard.send_email_notifications'
:
{
'task'
:
'dashboard.tasks.local_periodic_tasks.'
'task'
:
'dashboard.tasks.local_periodic_tasks.'
'send_email_notifications'
,
'send_email_notifications'
,
'schedule'
:
timedelta
(
hours
=
24
),
'schedule'
:
crontab
(
minute
=
10
,
hour
=
1
),
'options'
:
{
'queue'
:
'localhost.man'
}
'options'
:
{
'queue'
:
'localhost.man'
}
},
},
}
}
...
...
circle/storage/models.py
View file @
5179872f
...
@@ -86,7 +86,7 @@ class DataStore(Model):
...
@@ -86,7 +86,7 @@ class DataStore(Model):
args
=
[
self
.
path
],
queue
=
q
)
.
get
(
timeout
=
timeout
)
args
=
[
self
.
path
],
queue
=
q
)
.
get
(
timeout
=
timeout
)
@method_cache
(
30
)
@method_cache
(
30
)
def
get_orphan_disks
(
self
,
timeout
=
1
5
):
def
get_orphan_disks
(
self
,
timeout
=
2
5
):
"""Disk image files without Disk object in the database.
"""Disk image files without Disk object in the database.
"""
"""
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
...
@@ -101,7 +101,7 @@ class DataStore(Model):
...
@@ -101,7 +101,7 @@ class DataStore(Model):
return
orphans
return
orphans
@method_cache
(
30
)
@method_cache
(
30
)
def
get_missing_disks
(
self
,
timeout
=
1
5
):
def
get_missing_disks
(
self
,
timeout
=
2
5
):
"""Disk objects without disk image files.
"""Disk objects without disk image files.
"""
"""
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
...
@@ -111,7 +111,7 @@ class DataStore(Model):
...
@@ -111,7 +111,7 @@ class DataStore(Model):
return
disks
.
exclude
(
filename__in
=
files
)
return
disks
.
exclude
(
filename__in
=
files
)
@method_cache
(
120
)
@method_cache
(
120
)
def
get_file_statistics
(
self
,
timeout
=
3
0
):
def
get_file_statistics
(
self
,
timeout
=
9
0
):
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
queue_name
=
self
.
get_remote_queue_name
(
'storage'
,
"slow"
)
data
=
storage_tasks
.
get_file_statistics
.
apply_async
(
data
=
storage_tasks
.
get_file_statistics
.
apply_async
(
args
=
[
self
.
path
],
queue
=
queue_name
)
.
get
(
timeout
=
timeout
)
args
=
[
self
.
path
],
queue
=
queue_name
)
.
get
(
timeout
=
timeout
)
...
...
circle/vm/models/node.py
View file @
5179872f
...
@@ -349,7 +349,7 @@ class Node(OperatedMixin, TimeStampedModel):
...
@@ -349,7 +349,7 @@ class Node(OperatedMixin, TimeStampedModel):
continue
continue
value
=
target
[
'datapoints'
][
-
2
][
0
]
value
=
target
[
'datapoints'
][
-
2
][
0
]
retval
[
metric
]
=
float
(
value
)
retval
[
metric
]
=
float
(
value
)
except
(
KeyError
,
IndexError
,
ValueError
):
except
(
KeyError
,
IndexError
,
ValueError
,
TypeError
):
continue
continue
return
retval
return
retval
...
...
circle/vm/operations.py
View file @
5179872f
...
@@ -460,7 +460,7 @@ class DeployOperation(InstanceOperation):
...
@@ -460,7 +460,7 @@ class DeployOperation(InstanceOperation):
description
=
_
(
"Deploy virtual machine."
)
description
=
_
(
"Deploy virtual machine."
)
remote_queue
=
(
"vm"
,
"slow"
)
remote_queue
=
(
"vm"
,
"slow"
)
task
=
vm_tasks
.
deploy
task
=
vm_tasks
.
deploy
remote_timeout
=
120
def
_get_remote_args
(
self
,
**
kwargs
):
def
_get_remote_args
(
self
,
**
kwargs
):
return
[
self
.
instance
.
get_vm_desc
()]
return
[
self
.
instance
.
get_vm_desc
()]
# intentionally not calling super
# intentionally not calling super
...
...
circle/vm/tasks/local_periodic_tasks.py
View file @
5179872f
...
@@ -58,9 +58,9 @@ def garbage_collector(timeout=15):
...
@@ -58,9 +58,9 @@ def garbage_collector(timeout=15):
i
.
pk
,
unicode
(
e
))
i
.
pk
,
unicode
(
e
))
elif
(
i
.
time_of_suspend
and
now
>
i
.
time_of_suspend
and
elif
(
i
.
time_of_suspend
and
now
>
i
.
time_of_suspend
and
i
.
state
==
'RUNNING'
):
i
.
state
==
'RUNNING'
):
i
.
sleep
.
async
(
system
=
True
)
logger
.
info
(
"Expired instance
%
d suspended."
%
i
.
pk
)
logger
.
info
(
"Expired instance
%
d suspended."
%
i
.
pk
)
try
:
try
:
i
.
sleep
.
async
(
system
=
True
)
i
.
owner
.
profile
.
notify
(
i
.
owner
.
profile
.
notify
(
ugettext_noop
(
'
%(instance)
s suspended'
),
ugettext_noop
(
'
%(instance)
s suspended'
),
ugettext_noop
(
ugettext_noop
(
...
@@ -68,8 +68,10 @@ def garbage_collector(timeout=15):
...
@@ -68,8 +68,10 @@ def garbage_collector(timeout=15):
'has been suspended due to expiration. '
'has been suspended due to expiration. '
'You can resume or destroy it.'
),
'You can resume or destroy it.'
),
instance
=
i
.
name
,
url
=
i
.
get_absolute_url
())
instance
=
i
.
name
,
url
=
i
.
get_absolute_url
())
except
ActivityInProgressError
:
logger
.
error
(
"Expired instance
%
d can't be destroyed due the AtctivityInPorgressError."
,
i
.
pk
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
debug
(
'Could not notify owner of instance
%
d .
%
s'
,
logger
.
info
(
'Could not notify owner of instance
%
d .
%
s'
,
i
.
pk
,
unicode
(
e
))
i
.
pk
,
unicode
(
e
))
elif
i
.
is_expiring
():
elif
i
.
is_expiring
():
logger
.
debug
(
"Instance
%
d expires soon."
%
i
.
pk
)
logger
.
debug
(
"Instance
%
d expires soon."
%
i
.
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