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
eae91fdd
authored
Dec 15, 2017
by
Czémán Arnold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard, manager, vm: adds basic auto migration view and fake auto_migrate task
parent
4d7f1820
Pipeline
#634
passed with stage
in 0 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
104 additions
and
2 deletions
+104
-2
circle/circle/settings/base.py
+3
-0
circle/dashboard/forms.py
+8
-0
circle/dashboard/static/dashboard/dashboard.less
+4
-0
circle/dashboard/static/dashboard/node-list.js
+7
-0
circle/dashboard/templates/dashboard/node-list.html
+19
-0
circle/dashboard/urls.py
+3
-0
circle/dashboard/views/node.py
+33
-2
circle/manager/mancelery.py
+19
-0
circle/vm/tasks/local_periodic_tasks.py
+8
-0
No files found.
circle/circle/settings/base.py
View file @
eae91fdd
...
...
@@ -587,3 +587,6 @@ REQUEST_HOOK_URL = get_env_variable("REQUEST_HOOK_URL", "")
SSHKEY_EMAIL_ADD_KEY
=
False
TWO_FACTOR_ISSUER
=
get_env_variable
(
"TWO_FACTOR_ISSUER"
,
"CIRCLE"
)
# Default value is every day at midnight
AUTO_MIGRATION_CRONTAB
=
get_env_variable
(
"AUTO_MIGRATION_CRONTAB"
,
"0 0 * * *"
)
circle/dashboard/forms.py
View file @
eae91fdd
...
...
@@ -1697,3 +1697,11 @@ class TwoFactorConfirmationForm(forms.Form):
totp
=
pyotp
.
TOTP
(
self
.
user
.
profile
.
two_factor_secret
)
if
not
totp
.
verify
(
self
.
cleaned_data
.
get
(
'confirmation_code'
)):
raise
ValidationError
(
_
(
"Invalid confirmation code."
))
class
AutoMigrationForm
(
forms
.
Form
):
minute
=
forms
.
CharField
()
hour
=
forms
.
CharField
()
day_of_month
=
forms
.
CharField
()
month_of_year
=
forms
.
CharField
()
day_of_week
=
forms
.
CharField
()
circle/dashboard/static/dashboard/dashboard.less
View file @
eae91fdd
...
...
@@ -1079,6 +1079,10 @@ textarea[name="new_members"] {
max-width: 100%;
}
#node-list-auto-migration-body {
padding: 20px;
}
#vm-list-table td.state,
#vm-list-table td.memory {
white-space: nowrap;
...
...
circle/dashboard/static/dashboard/node-list.js
View file @
eae91fdd
...
...
@@ -3,4 +3,11 @@ $(function() {
// find disabled nodes, set danger (red) on the rows
$
(
'.node-disabled'
).
closest
(
"tr"
).
addClass
(
'danger'
);
});
$
(
'#reschedule-now'
).
click
(
function
()
{
$
.
get
(
$
(
this
).
attr
(
'href'
),
function
(
data
){
highlight
=
data
.
result
===
'ok'
?
'success'
:
'danger'
;
addMessage
(
data
.
message
,
highlight
);
});
return
false
;
});
});
circle/dashboard/templates/dashboard/node-list.html
View file @
eae91fdd
...
...
@@ -41,4 +41,23 @@
</div>
<!-- -col-md-12 -->
</div>
<!-- .row -->
<div
class=
"row"
>
<div
class=
"col-md-12"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<a
id=
"reschedule-now"
class=
"btn btn-danger pull-right"
href=
"{% url "
dashboard
.
views
.
reschedule
"
%}"
>
<i
class=
"fa fa-magic"
></i>
{% trans "Reschedule now" %}
</a>
<h3
class=
"no-margin"
><i
class=
"fa fa-truck"
></i>
{% trans "Virtual machine auto migration" %}
</h3>
</div>
<div
id=
"node-list-auto-migration-body"
>
<h1>
Crontab
</h1>
<form>
{{ auto_migration_form.as_p }}
</form>
</div>
</div>
</div>
<!-- -col-md-12 -->
</div>
<!-- .row -->
{% endblock %}
circle/dashboard/urls.py
View file @
eae91fdd
...
...
@@ -56,6 +56,7 @@ from .views import (
MessageList
,
MessageDetail
,
MessageCreate
,
MessageDelete
,
EnableTwoFactorView
,
DisableTwoFactorView
,
AclUserGroupAutocomplete
,
AclUserAutocomplete
,
RescheduleView
,
)
from
.views.vm
import
vm_ops
,
vm_mass_ops
from
.views.node
import
node_ops
...
...
@@ -153,6 +154,8 @@ urlpatterns = [
r'(?P<time>[0-9]{1,2}[hdwy])$'
),
NodeListGraphView
.
as_view
(),
name
=
'dashboard.views.node-list-graph'
),
url
(
r'^node/reschedule/$'
,
RescheduleView
.
as_view
(),
name
=
"dashboard.views.reschedule"
),
url
((
r'^template/(?P<pk>\d+)/graph/(?P<metric>[a-z]+)/'
r'(?P<time>[0-9]{1,2}[hdwy])$'
),
TemplateGraphView
.
as_view
(),
...
...
circle/dashboard/views/node.py
View file @
eae91fdd
...
...
@@ -25,7 +25,7 @@ from django.core.exceptions import PermissionDenied
from
django.core.urlresolvers
import
reverse_lazy
from
django.db.models
import
Count
from
django.forms.models
import
inlineformset_factory
from
django.http
import
HttpResponse
from
django.http
import
HttpResponse
,
JsonResponse
from
django.shortcuts
import
redirect
from
django.template.loader
import
render_to_string
from
django.utils.translation
import
ugettext
as
_
...
...
@@ -37,11 +37,14 @@ from django_tables2 import SingleTableView
from
firewall.models
import
Host
from
vm.models
import
Node
,
NodeActivity
,
Trait
from
vm.tasks.vm_tasks
import
check_queue
from
vm.tasks.local_periodic_tasks
import
auto_migrate
from
..forms
import
TraitForm
,
HostForm
,
NodeForm
from
..forms
import
TraitForm
,
HostForm
,
NodeForm
,
AutoMigrationForm
from
..tables
import
NodeListTable
from
.util
import
AjaxOperationMixin
,
OperationView
,
GraphMixin
,
DeleteViewBase
from
manager.mancelery
import
crontab_parser
def
get_operations
(
instance
,
user
):
ops
=
[]
...
...
@@ -190,6 +193,14 @@ class NodeList(LoginRequiredMixin, GraphMixin, SingleTableView):
table_class
=
NodeListTable
table_pagination
=
False
def
get_crontab
(
self
):
return
crontab_parser
(
settings
.
AUTO_MIGRATION_CRONTAB
)
def
get_context_data
(
self
):
context
=
super
(
NodeList
,
self
)
.
get_context_data
()
context
[
"auto_migration_form"
]
=
AutoMigrationForm
(
self
.
get_crontab
())
return
context
def
get
(
self
,
*
args
,
**
kwargs
):
if
not
self
.
request
.
user
.
has_perm
(
'vm.view_statistics'
):
raise
PermissionDenied
()
...
...
@@ -356,3 +367,23 @@ class NodeActivityDetail(LoginRequiredMixin, SuperuserRequiredMixin,
)
.
order_by
(
'-started'
)
.
select_related
())
ctx
[
'icon'
]
=
_get_activity_icon
(
self
.
object
)
return
ctx
class
RescheduleView
(
SuperuserRequiredMixin
,
View
):
def
get
(
self
,
*
args
,
**
kwargs
):
try
:
auto_migrate
.
apply_async
(
queue
=
'localhost.man.slow'
)
except
Exception
as
e
:
msg
=
str
(
e
)
result
=
'error'
else
:
result
=
'ok'
msg
=
_
(
'Reschedule has started.'
)
if
self
.
request
.
is_ajax
():
return
JsonResponse
({
'result'
:
result
,
'message'
:
msg
})
else
:
if
result
==
'ok'
:
messages
.
success
(
self
.
request
,
msg
)
else
:
messages
.
error
(
self
.
request
,
msg
)
return
redirect
(
'dashboard.views.node-list'
)
circle/manager/mancelery.py
View file @
eae91fdd
...
...
@@ -17,12 +17,26 @@
from
celery
import
Celery
from
celery.signals
import
worker_ready
from
celery.schedules
import
crontab
from
datetime
import
timedelta
from
kombu
import
Queue
,
Exchange
from
os
import
getenv
HOSTNAME
=
"localhost"
QUEUE_NAME
=
HOSTNAME
+
'.man'
AUTO_MIGRATION_CRONTAB
=
getenv
(
'AUTO_MIGRATION_CRONTAB'
,
'0 0 * * *'
)
def
crontab_parser
(
crontab
):
fields
=
crontab
.
split
(
' '
)
return
dict
(
minute
=
fields
[
0
],
hour
=
fields
[
1
],
day_of_month
=
fields
[
2
],
month_of_year
=
fields
[
3
],
day_of_week
=
fields
[
4
],
)
celery
=
Celery
(
'manager'
,
...
...
@@ -55,6 +69,11 @@ celery.conf.update(
'schedule'
:
timedelta
(
hours
=
24
),
'options'
:
{
'queue'
:
'localhost.man'
}
},
'vm.local_periodic_tasks'
:
{
'task'
:
'vm.tasks.local_periodic_tasks.auto_migrate'
,
'schedule'
:
crontab
(
**
crontab_parser
(
AUTO_MIGRATION_CRONTAB
)),
'options'
:
{
'queue'
:
'localhost.man.slow'
},
},
}
)
...
...
circle/vm/tasks/local_periodic_tasks.py
View file @
eae91fdd
...
...
@@ -76,3 +76,11 @@ def garbage_collector(timeout=15):
i
.
notify_owners_about_expiration
()
else
:
logger
.
debug
(
"Instance
%
d didn't expire."
%
i
.
pk
)
@celery.task
(
ignore_result
=
True
)
def
auto_migrate
():
# Dummy implementation
import
time
logger
.
info
(
"Auto migration has started."
)
time
.
sleep
(
10
)
logger
.
info
(
"Auto migration has finished."
)
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