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:
Radomir Dopieralski
2014-09-30 16:01:35 +02:00
parent 0f5690d640
commit f0533f6d5c
6 changed files with 135 additions and 26 deletions

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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>

View File

@@ -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)

View File

@@ -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;
} ());

View File

@@ -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 %}