Refresh progress page with AJAX
Instead of reloading the progress page constantly, update it with JavaScript. Only refresh when the deployment finished. Change-Id: I2c08c6f213dad59f410f6e5612fd1c2ed89f7eec
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
{% load i18n %}
|
||||
{% load url from future%}
|
||||
{% load horizon %}
|
||||
|
||||
{% block deployment-icon %}
|
||||
<i class="fa fa-spinner fa-spin text-info"></i>
|
||||
@@ -28,6 +29,7 @@
|
||||
><span class="sr-only">{{ progress }}% {% trans "Complete" %}</span></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="deploy-last-events'>
|
||||
{% if last_failed_events %}
|
||||
<strong>{% trans "Last failed events:" %}</strong>
|
||||
{% for event in last_failed_events %}
|
||||
@@ -46,6 +48,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<p><a href="{% url 'horizon:infrastructure:history:index' %}">See full log</a></p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block deployment-buttons %}
|
||||
@@ -59,3 +62,22 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block templates %}
|
||||
<script type="text/html" id="events-template">{% spaceless %}{% jstemplate %}
|
||||
<strong>{% trans "Last failed events:" %}</strong>
|
||||
[[#last_failed_events]]
|
||||
<div>
|
||||
<dl>
|
||||
<dt>{% trans "Timestamp" %}</dt>
|
||||
<dd><time datetime="[[ event_time ]]">[[ event_time ]]</time></dd>
|
||||
<dt>{% trans "Resource Name" %}</dt>
|
||||
<dd>[[ resource_name ]]</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>[[ resource_status ]]</dd>
|
||||
<dt>{% trans "Reason" %}</dt>
|
||||
<dd>[[ resource_status_reason ]]</dd>
|
||||
</dl>
|
||||
</div>
|
||||
[[/last_failed_events]]
|
||||
{% endjstemplate %}{% endspaceless %}</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,13 +4,6 @@
|
||||
|
||||
{% block title %}{% trans 'My OpenStack Deployment' %}{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{% if stack.is_deploying %}
|
||||
<meta http-equiv="refresh" content="30">
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_domain_page_header.html' with title=_('My OpenStack Deployment') %}
|
||||
{% endblock page_header %}
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% load horizon %}
|
||||
|
||||
<h4>{% trans "Deployment Roles" %}</h4>
|
||||
<div class="deploy-role-status">
|
||||
{% for role in roles %}
|
||||
<div class="alert well-sm clearfix
|
||||
{% if role.error_node_count %}
|
||||
alert-danger
|
||||
{% elif role.deployed_node_count == role.planned_node_count %}
|
||||
alert-success
|
||||
{% else %}
|
||||
alert-info
|
||||
{% endif %}
|
||||
">
|
||||
<div class="alert well-sm clearfix alert-{{ role.status }}">
|
||||
<div class="col-sm-2">
|
||||
{% if role.deployed_node_count < role.planned_node_count %}
|
||||
{% if role.finished %}
|
||||
<strong>{{ role.deployed_node_count }}</strong><small class="text-muted">/{{ role.planned_node_count }}</small>
|
||||
{% else %}
|
||||
<strong>{{ role.planned_node_count }}</strong>
|
||||
@@ -26,3 +20,22 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="roles-template">{% spaceless %}{% jstemplate %}
|
||||
[[#roles]]
|
||||
<div class="alert well-sm clearfix alert-[[status]]">
|
||||
<div class="col-sm-2">
|
||||
[[#finished]]
|
||||
<strong>[[ planned_node_count ]]</strong>
|
||||
[[/finished]]
|
||||
[[^finished]]
|
||||
<strong>[[ deployed_node_count ]]
|
||||
</strong><small class="text-muted">/[[ planned_node_count ]]</small>
|
||||
[[/finished]]
|
||||
</div>
|
||||
<div class="col-sm-10"><strong>[[ name ]]</strong></div>
|
||||
</div>
|
||||
[[/roles]]
|
||||
{% endjstemplate %}{% endspaceless %}</script>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ def _get_role_data(plan, stack, form, role):
|
||||
'role': role,
|
||||
'name': role.name,
|
||||
'planned_node_count': plan.get_role_node_count(role),
|
||||
'field': form['%s-count' % role.id],
|
||||
'field': form['%s-count' % role.id] if form else '',
|
||||
}
|
||||
|
||||
if stack:
|
||||
@@ -55,6 +55,7 @@ def _get_role_data(plan, stack, form, role):
|
||||
error_node_count = 0
|
||||
waiting_node_count = node_count
|
||||
|
||||
status = 'warning'
|
||||
if nodes:
|
||||
deployed_node_count = sum(1 for node in nodes
|
||||
if node.instance.status == 'ACTIVE')
|
||||
@@ -64,7 +65,16 @@ def _get_role_data(plan, stack, form, role):
|
||||
if node.instance.status == 'ERROR')
|
||||
waiting_node_count = (node_count - deployed_node_count -
|
||||
deploying_node_count - error_node_count)
|
||||
if error_node_count:
|
||||
status = 'danger'
|
||||
elif deployed_node_count == data['planned_node_count']:
|
||||
status = 'success'
|
||||
else:
|
||||
status = 'info'
|
||||
|
||||
data.update({
|
||||
'status': status,
|
||||
'finished': deployed_node_count == data['planned_node_count'],
|
||||
'total_node_count': node_count,
|
||||
'deployed_node_count': deployed_node_count,
|
||||
'deploying_node_count': deploying_node_count,
|
||||
@@ -93,6 +103,33 @@ class IndexView(horizon.forms.ModalFormView, StackMixin):
|
||||
form_class = forms.EditPlan
|
||||
success_url = reverse_lazy(INDEX_URL)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if request.META.get('HTTP_X_HORIZON_PROGRESS', ''):
|
||||
data = self.get_data(request, {})
|
||||
return http.HttpResponse(json.dumps({
|
||||
'progress': data.get('progress'),
|
||||
'last_failed_events': [{
|
||||
'event_time': event.event_time,
|
||||
'resource_name': event.resource_name,
|
||||
'resource_status': event.resource_status,
|
||||
'resource_statys_reason': event.resource_statys_reason,
|
||||
} for event in data.get('last_failed_events', [])],
|
||||
'roles': [{
|
||||
'status': role.get('status', 'warning'),
|
||||
'finished': role.get('finished', False),
|
||||
'name': role.get('name', ''),
|
||||
'id': role.get('id', ''),
|
||||
'total_node_count': role.get('node_count', 0),
|
||||
'deployed_node_count': role.get('deployed_node_count', 0),
|
||||
'deploying_node_count': role.get('deploying_node_count',
|
||||
0),
|
||||
'waiting_node_count': role.get('waiting_node_count', 0),
|
||||
'error_node_count': role.get('error_node_count', 0),
|
||||
'planned_node_count': role.get('planned_node_count', 0),
|
||||
} for role in data.get('roles', [])],
|
||||
}), mimetype='application/json')
|
||||
return super(IndexView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_form(self, form_class):
|
||||
return form_class(self.request, **self.get_form_kwargs())
|
||||
|
||||
@@ -104,7 +141,7 @@ class IndexView(horizon.forms.ModalFormView, StackMixin):
|
||||
def get_data(self, request, context, *args, **kwargs):
|
||||
plan = api.tuskar.Plan.get_the_plan(request)
|
||||
stack = self.get_stack()
|
||||
form = context['form']
|
||||
form = context.get('form')
|
||||
|
||||
context['plan'] = plan
|
||||
context['stack'] = stack
|
||||
@@ -141,19 +178,21 @@ class IndexView(horizon.forms.ModalFormView, StackMixin):
|
||||
total_num_nodes_count = max(
|
||||
resources_count, total_num_nodes_count)
|
||||
|
||||
context['progress'] = max(
|
||||
5, 100 * (total_num_nodes_count - resources_count))
|
||||
context['progress'] = min(95, max(
|
||||
5, 100 * float(resources_count) / total_num_nodes_count))
|
||||
elif stack.is_deploying:
|
||||
total = sum(d['total_node_count'] for d in roles)
|
||||
context['progress'] = min(95, max(
|
||||
5, 100 * sum(float(d.get('deployed_node_count', 0))
|
||||
for d in roles) / (total or 1)
|
||||
))
|
||||
else:
|
||||
# stack is active
|
||||
context['progress'] = 100
|
||||
controller_role = plan.get_role_by_name("controller")
|
||||
context['admin_password'] = plan.parameter_value(
|
||||
controller_role.parameter_prefix + 'AdminPassword')
|
||||
|
||||
total = sum(d['total_node_count'] for d in roles)
|
||||
context['progress'] = max(
|
||||
5, 100 * sum(d.get('deployed_node_count', 0)
|
||||
for d in roles) // (total or 1)
|
||||
)
|
||||
context['dashboard_urls'] = stack.dashboard_urls
|
||||
else:
|
||||
messages = forms.validate_plan(request, plan)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
tuskar.deployment_progress = (function () {
|
||||
'use strict';
|
||||
|
||||
var module = {};
|
||||
|
||||
module.init = function () {
|
||||
if (!$('div.deployment-box div.progress')) { return; }
|
||||
module.interval = setInterval(module.check_progress, 30000);
|
||||
module.events_template = Hogan.compile($('#events-template').html() || '');
|
||||
module.roles_template = Hogan.compile($('#roles-template').html() || '');
|
||||
};
|
||||
|
||||
module.check_progress = function () {
|
||||
var $form = $('form.deployment-roles-form');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
headers: {'X-Horizon-Progress': 'true'},
|
||||
url: $form.attr('action'),
|
||||
dataType: 'json',
|
||||
async: true,
|
||||
success: module.update_progress
|
||||
});
|
||||
};
|
||||
|
||||
module.update_progress = function (data) {
|
||||
if (data.progress >= 100 || data.progress <= 0) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
var $bar = $('div.deployment-box div.progress div.progress-bar');
|
||||
$bar.css('width', '' + data.progress + '%');
|
||||
if (data.last_failed_events) {
|
||||
$('div.deploy-last-events').html(module.events_template.render(data));
|
||||
} else {
|
||||
$('div.deploy-last-events').html('');
|
||||
}
|
||||
$('div.deploy-role-status').html(module.roles_template.render(data));
|
||||
};
|
||||
|
||||
horizon.addInitFunction(module.init);
|
||||
return module;
|
||||
} ());
|
||||
@@ -8,6 +8,7 @@
|
||||
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.menu_formset.js' type='text/javascript' charset='utf-8'></script>
|
||||
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.number_picker.js' type='text/javascript' charset='utf-8'></script>
|
||||
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.edit_plan.js' type='text/javascript' charset='utf-8'></script>
|
||||
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.deployment_progress.js' type='text/javascript' charset='utf-8'></script>
|
||||
{% endblock %}
|
||||
|
||||
{% comment %} Tuskar-UI Client-side Templates (These should *not* be inside the "compress" tag.) {% endcomment %}
|
||||
|
||||
Reference in New Issue
Block a user