Merge "Add sexy boxes to the deployment status page"

This commit is contained in:
Jenkins 2014-11-24 20:09:07 +00:00 committed by Gerrit Code Review
commit bdc4f301c7
4 changed files with 103 additions and 22 deletions

View File

@ -17,6 +17,20 @@ from tuskar_ui.infrastructure.overview import views
from tuskar_boxes.overview import forms
NODE_STATE_ICON = {
api.node.DISCOVERING_STATE: 'fa-search',
api.node.DISCOVERED_STATE: 'fa-search-plus',
api.node.DISCOVERY_FAILED_STATE: 'fa-search-minus',
api.node.MAINTENANCE_STATE: 'fa-exclamation-triangle',
api.node.FREE_STATE: 'fa-minus',
api.node.PROVISIONING_STATE: 'fa-spinner fa-spin',
api.node.PROVISIONED_STATE: 'fa-check',
api.node.DELETING_STATE: 'fa-spinner fa-spin',
api.node.PROVISIONING_FAILED_STATE: 'fa-exclamation-circle',
None: 'fa-question',
}
def flavor_nodes(request, flavor):
"""Lists all nodes that match the given flavor exactly."""
for node in api.node.Node.list(request, maintenance=False):
@ -29,6 +43,14 @@ def flavor_nodes(request, flavor):
yield node
def node_role(request, node):
try:
resource = api.heat.Resource.get_by_node(request, node)
except LookupError:
return None
return resource.role
class IndexView(views.IndexView):
template_name = "tuskar_boxes/overview/index.html"
form_class = forms.EditPlan
@ -40,27 +62,35 @@ class IndexView(views.IndexView):
for role in context['roles']:
flavor = role['role'].flavor(context['plan'])
role['flavor_name'] = flavor.name if flavor else ''
context['flavors'] = []
for flavor in flavors:
nodes = [{
'role': '',
} for node in flavor_nodes(self.request, flavor)]
roles = [role for role in context['roles']
if role['flavor_name'] == flavor.name]
flavor = {
'name': flavor.name,
'vcpus': flavor.vcpus,
'ram': flavor.ram,
'disk': flavor.disk,
'cpu_arch': flavor.cpu_arch,
'nodes': nodes,
'roles': roles,
}
if nodes or roles: # Don't list empty flavors
context['flavors'].append(flavor)
context['free_roles'] = [role for role in context['roles']
if not role['flavor_name']]
if not context['stack']:
context['flavors'] = []
for flavor in flavors:
nodes = [{
'role': '',
} for node in flavor_nodes(self.request, flavor)]
roles = [role for role in context['roles']
if role['flavor_name'] == flavor.name]
flavor = {
'name': flavor.name,
'vcpus': flavor.vcpus,
'ram': flavor.ram,
'disk': flavor.disk,
'cpu_arch': flavor.cpu_arch,
'nodes': nodes,
'roles': roles,
}
if nodes or roles: # Don't list empty flavors
context['flavors'].append(flavor)
context['free_roles'] = [role for role in context['roles']
if not role['flavor_name']]
for role in context['roles']:
role['flavor_field'] = context['form'][role['id'] + '-flavor']
else:
context['nodes'] = [{
'uuid': node.uuid,
'role': node_role(self.request, node),
'state': node.state,
'state_icon': NODE_STATE_ICON.get(node.state,
NODE_STATE_ICON[None]),
} for node in api.node.Node.list(self.request, maintenance=False)]
return context

View File

@ -29,12 +29,15 @@
opacity: 0.75;
padding: 6px;
border: 1px solid;
cursor: move;
border-radius: 2px;
background-color: #fce94f;
border-color: #edd400;
color: #c4a000;
margin: 0 0 4px 0;
cursor: move;
}
.deploy-role-status .boxes-role {
cursor: default;
}
.boxes-available-roles .boxes-role {
display: inline-block;

View File

@ -42,7 +42,7 @@
</div>
<div class="col-xs-8">
{% if stack %}
{% include "infrastructure/overview/role_nodes_status.html" %}
{% include "tuskar_boxes/overview/role_nodes_status.html" %}
{% else %}
{% include "tuskar_boxes/overview/role_nodes_edit.html" %}
{% endif %}

View File

@ -0,0 +1,48 @@
{% load i18n %}
{% load url from future %}
{% load horizon %}
<h4>{% trans "Deployment Roles" %}</h4>
<div class="row">
<div class="deploy-role-status col-xs-5">
{% for role in roles %}
<div class="boxes-role boxes-role-{{ role.name|slugify }} clearfix">
<div class="col-xs-2 deploy-role-count">
{% if role.finished %}
{{ role.deployed_node_count }}
{% else %}
{{ role.deployed_node_count }}<small class="text-muted">/{{ role.planned_node_count }}</small>
{% endif %}
</div>
<div class="col-xs-10 deploy-role-name">
<strong class="deployment-roles-label">{{ role.name|capfirst }}</strong>
</div>
</div>
{% endfor %}
</div>
<div class="col-xs-7 boxes-nodes">
{% for node in nodes %}{% spaceless %}
<div class="boxes-node boxes-role-{{ node.role.name|slugify }} status-{{ node.status|slugify }}" title="{{ node.uuid }}">
<i class="fa fa-lg {{ node.state_icon }}"></i>
</div>
{% endspaceless %}{% endfor %}
</div>
</div>
<script type="text/html" id="roles-template">{% spaceless %}{% jstemplate %}
[[#roles]]
<div class="boxes-role boxes-role boxes-role[[ slug ]] clearfix">
<div class="col-xs-2 deploy-role-count">
[[#finished]]
[[ deployed_node_count ]]
[[/finished]]
[[^finished]]
[[ deployed_node_count ]]<small class="text-muted">/[[ planned_node_count ]]</small>
[[/finished]]
</div>
<div class="col-xs-10 deploy-role-name">
<strong class="deployment-roles-label" >[[ name ]]</strong>
</div>
</div>
[[/roles]]
{% endjstemplate %}{% endspaceless %}</script>