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