Sexy boxes drag and drop
The plan edit page is modified to show the flavors with a visualisation of the nodes. Roles can be dragged and dropped on the flavors. TODO: actually save the flavor for a role in the form TODO: add a popup for adding the roles to flavors Change-Id: I9b97f39e3800b5b6c2e5639fcfd186b4196d0190
This commit is contained in:
parent
f1bf2337ae
commit
05e505c5c6
@ -7,7 +7,7 @@ include AUTHORS
|
|||||||
include LICENSE
|
include LICENSE
|
||||||
include Makefile
|
include Makefile
|
||||||
include manage.py
|
include manage.py
|
||||||
include README.md
|
include README.rst
|
||||||
include run_tests.sh
|
include run_tests.sh
|
||||||
include tox.ini
|
include tox.ini
|
||||||
include doc/Makefile
|
include doc/Makefile
|
||||||
|
@ -16,7 +16,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
import horizon
|
import horizon
|
||||||
|
|
||||||
from tuskar_ui.infrastructure import dashboard
|
import tuskar_ui.infrastructure.dashboard as tuskar_dashboard
|
||||||
|
from tuskar_ui.infrastructure.overview.panel import Overview as TuskarOverview
|
||||||
|
|
||||||
|
|
||||||
class Overview(horizon.Panel):
|
class Overview(horizon.Panel):
|
||||||
@ -24,4 +25,5 @@ class Overview(horizon.Panel):
|
|||||||
slug = "overview"
|
slug = "overview"
|
||||||
|
|
||||||
|
|
||||||
dashboard.Infrastructure.register(Overview)
|
tuskar_dashboard.Infrastructure.unregister(TuskarOverview)
|
||||||
|
tuskar_dashboard.Infrastructure.register(Overview)
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
{% extends "horizon/common/_modal_form.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future %}
|
|
||||||
|
|
||||||
{% block form_id %}provision_form{% endblock %}
|
|
||||||
{% block form_action %}{% url 'horizon:infrastructure:overview:deploy_confirmation' %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal_id %}provision_modal{% endblock %}
|
|
||||||
{% block modal-header %}{% trans "Deployment Confirmation" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-body %}
|
|
||||||
<div>
|
|
||||||
<p>{% trans "You are about deploy your overcloud" %}
|
|
||||||
</p>
|
|
||||||
{% if autogenerated_parameters %}
|
|
||||||
<strong>These parameters will be randomly generated before the deployment:</strong>
|
|
||||||
<p>{{ autogenerated_parameters|join:", " }}</p>
|
|
||||||
{% endif %}
|
|
||||||
<p>{% trans "This operation cannot be undone. Are you sure you want to do that?" %}</p>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-footer %}
|
|
||||||
<input class="btn btn-primary" type="submit" value="{% trans "Deploy" %}" />
|
|
||||||
<a href="{% url 'horizon:infrastructure:overview:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
|
||||||
{% endblock %}
|
|
@ -1,27 +0,0 @@
|
|||||||
{% extends "horizon/common/_modal_form.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future %}
|
|
||||||
|
|
||||||
{% block form_id %}post_deploy_init_form{% endblock %}
|
|
||||||
{% block form_action %}{% url 'horizon:infrastructure:overview:post_deploy_init' %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal_id %}provision_modal{% endblock %}
|
|
||||||
{% block modal-header %}{% trans "Initialize Overcloud" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-body %}
|
|
||||||
<div>
|
|
||||||
<fieldset>
|
|
||||||
<div class="left">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
{% trans "Your OpenStack cloud nodes are deployed. They need to be initialized before your cloud will be live."%}
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-footer %}
|
|
||||||
<input class="btn btn-primary" type="submit" value="{% trans "Initialize" %}" />
|
|
||||||
<a href="{% url 'horizon:infrastructure:overview:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
|
||||||
{% endblock %}
|
|
@ -1,25 +0,0 @@
|
|||||||
{% extends "horizon/common/_modal_form.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future %}
|
|
||||||
|
|
||||||
{% block form_id %}provision_form{% endblock %}
|
|
||||||
{% block form_action %}{% url 'horizon:infrastructure:overview:undeploy_confirmation' %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal_id %}provision_modal{% endblock %}
|
|
||||||
{% block modal-header %}{% trans "Undeployment Confirmation" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-body %}
|
|
||||||
<div>
|
|
||||||
<p>{% trans "You are about undeploy your overcloud" %}
|
|
||||||
</p>
|
|
||||||
<p>{% trans "This operation cannot be undone. Are you sure you want to do that?" %}</p>
|
|
||||||
<fieldset>
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block modal-footer %}
|
|
||||||
<input class="btn btn-primary" type="submit" value="{% trans "Undeploy" %}" />
|
|
||||||
<a href="{% url 'horizon:infrastructure:overview:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
|
||||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'infrastructure/base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Deploy overcloud" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Deploy overcloud") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block infrastructure_main %}
|
|
||||||
{% include "infrastructure/overview/_deploy_confirmation.html" %}
|
|
||||||
{% endblock %}
|
|
@ -1,22 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
<div class="deployment-icon">
|
|
||||||
{% block deployment-icon %}
|
|
||||||
<i class="fa fa-cloud text-info"></i>
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
<div class="deployment-box clearfix">
|
|
||||||
<h4>{% block deployment-title %}{% endblock %}</h4>
|
|
||||||
{% block deployment-info %}{% endblock %}
|
|
||||||
<div class="deployment-buttons clearfix">
|
|
||||||
{% block deployment-buttons %}
|
|
||||||
<a
|
|
||||||
href="{% url 'horizon:infrastructure:overview:undeploy_confirmation' %}"
|
|
||||||
class="btn btn-danger ajax-modal">
|
|
||||||
<i class="fa fa-trash"></i>
|
|
||||||
{% trans "Undeploy" %}
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,44 +0,0 @@
|
|||||||
{% extends "infrastructure/overview/deployment_base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
{% block deployment-icon %}
|
|
||||||
<i class="fa fa-exclamation-circle text-danger"></i>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-title %}
|
|
||||||
{% if stack.is_delete_failed %}
|
|
||||||
{% trans "Undeploying failed" %}
|
|
||||||
{% elif stack.is_failed %}
|
|
||||||
{% trans "Deployment failed" %}
|
|
||||||
{% else %}
|
|
||||||
{% trans "Failure" %}
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-info %}
|
|
||||||
{% if last_failed_events %}
|
|
||||||
<strong>{% trans "Last failed events:" %}</strong>
|
|
||||||
{% for event in last_failed_events %}
|
|
||||||
<div>
|
|
||||||
<dl>
|
|
||||||
<dt>{% trans "Timestamp" %}</dt>
|
|
||||||
<dd><time datetime="{{ event.event_time }}">{{ event.event_time }}</time></dd>
|
|
||||||
<dt>{% trans "Resource Name" %}</dt>
|
|
||||||
<dd>{{ event.resource_name }}</dd>
|
|
||||||
<dt>{% trans "Status" %}</dt>
|
|
||||||
<dd>{{ event.resource_status }}</dd>
|
|
||||||
<dt>{% trans "Reason" %}</dt>
|
|
||||||
<dd>{{ event.resource_status_reason }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<p><a href="{% url 'horizon:infrastructure:history:index' %}">See full log</a></p>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-buttons %}
|
|
||||||
{{ block.super }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
{% extends "infrastructure/overview/deployment_base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
{% block deployment-icon %}
|
|
||||||
<i class="fa fa-exclamation-triangle text-warning"></i>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-title %}{% trans "Initialization" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-info %}
|
|
||||||
<p>{% trans "Your OpenStack cloud is deployed but it needs to get initialized in order to get live." %}</p>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-buttons %}
|
|
||||||
{{ block.super }}
|
|
||||||
<a href="{% url 'horizon:infrastructure:overview:post_deploy_init' %}"
|
|
||||||
class="btn btn-primary ajax-modal">
|
|
||||||
<i class="fa fa-flag-checkered"></i>
|
|
||||||
{% trans "Initialize" %}
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
@ -1,33 +0,0 @@
|
|||||||
{% extends "infrastructure/overview/deployment_base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
{% block deployment-icon %}
|
|
||||||
<i class="fa fa-check-circle-o text-success"></i>
|
|
||||||
{% endblock %}
|
|
||||||
{% block deployment-title %}{% trans "Deployment is live" %}{% endblock %}
|
|
||||||
{% block deployment-info %}
|
|
||||||
<strong>{% trans "Access information" %}</strong>
|
|
||||||
<dl>
|
|
||||||
{% for dashboard_url in dashboard_urls %}
|
|
||||||
<dt>{% trans "Horizon URL" %}</dt>
|
|
||||||
<dd><a href="{{ dashboard_url }}">{{ dashboard_url }}</a></dd>
|
|
||||||
{% endfor %}
|
|
||||||
<dt>{% trans "User name" %}</dt>
|
|
||||||
<dd>admin</dd>
|
|
||||||
<dt></dt>
|
|
||||||
<dd>
|
|
||||||
<form>
|
|
||||||
<fieldset>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label required" for="id_password">{% trans "Password" %}</label>
|
|
||||||
<div>
|
|
||||||
<input class="form-control" id="id_password" type="password" value="{{ admin_password }}" disabled="true" readonly="true"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
{% endblock %}
|
|
@ -1,43 +0,0 @@
|
|||||||
{% extends "infrastructure/overview/deployment_base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
{% block deployment-icon %}
|
|
||||||
{% if plan_invalid %}
|
|
||||||
<i class="fa fa-exclamation-circle text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check-circle text-success"></i>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-title %}
|
|
||||||
{% if plan_invalid %}
|
|
||||||
{% trans "Design your deployment" %}
|
|
||||||
{% else %}
|
|
||||||
{% trans "Ready to get deployed" %}
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-info %}
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
{% for message in plan_messages %}
|
|
||||||
<li class="{% if message.is_critical %}text-danger{% else %}text-warning{% endif %}"><p>
|
|
||||||
{{ message.text }}
|
|
||||||
{% if message.link_url %}
|
|
||||||
<a href="{{ message.link_url }}">
|
|
||||||
{{ message.link_label|default:message.link_url }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</p></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-buttons %}
|
|
||||||
<a href="{% url 'horizon:infrastructure:overview:deploy_confirmation' %}"
|
|
||||||
class="btn btn-primary ajax-modal btn-default {% if plan_invalid %}disabled{% endif %}">
|
|
||||||
<i class="fa fa-rocket"></i>
|
|
||||||
{% trans "Deploy" %}
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
@ -1,61 +0,0 @@
|
|||||||
{% extends "infrastructure/overview/deployment_base.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
{% load url from future%}
|
|
||||||
|
|
||||||
{% block deployment-icon %}
|
|
||||||
<i class="fa fa-spinner text-info"></i>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-title %}
|
|
||||||
{% if stack.is_deleting %}
|
|
||||||
{% trans "Undeploying..." %}
|
|
||||||
{% elif stack.is_deploying %}
|
|
||||||
{% trans "Deploying..." %}
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-info %}
|
|
||||||
{% if progress %}
|
|
||||||
<div class="progress">
|
|
||||||
<div
|
|
||||||
class="progress-bar progress-bar-striped active"
|
|
||||||
role="progressbar"
|
|
||||||
aria-valuenow="{{ progress }}"
|
|
||||||
aria-valuemin="0"
|
|
||||||
aria-valuemax="100"
|
|
||||||
style="width: {{ progress }}%"
|
|
||||||
><span class="sr-only">{{ progress }}% {% trans "Complete" %}</span></div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if last_failed_events %}
|
|
||||||
<strong>{% trans "Last failed events:" %}</strong>
|
|
||||||
{% for event in last_failed_events %}
|
|
||||||
<div>
|
|
||||||
<dl>
|
|
||||||
<dt>{% trans "Timestamp" %}</dt>
|
|
||||||
<dd><time datetime="{{ event.event_time }}">{{ event.event_time }}</time></dd>
|
|
||||||
<dt>{% trans "Resource Name" %}</dt>
|
|
||||||
<dd>{{ event.resource_name }}</dd>
|
|
||||||
<dt>{% trans "Status" %}</dt>
|
|
||||||
<dd>{{ event.resource_status }}</dd>
|
|
||||||
<dt>{% trans "Reason" %}</dt>
|
|
||||||
<dd>{{ event.resource_status_reason }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<p><a href="{% url 'horizon:infrastructure:history:index' %}">See full log</a></p>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block deployment-buttons %}
|
|
||||||
{% if stack.is_deploying %}
|
|
||||||
<a
|
|
||||||
href="{% url 'horizon:infrastructure:overview:undeploy_confirmation' %}"
|
|
||||||
class="btn btn-danger ajax-modal">
|
|
||||||
<i class="fa fa-close"></i>
|
|
||||||
{% trans "Stop" %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'infrastructure/base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Initialize" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Initialize Overcloud") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block infrastructure_main %}
|
|
||||||
{% include "infrastructure/overview/_post_deploy_init.html" %}
|
|
||||||
{% endblock %}
|
|
@ -1,32 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
{% load url from future %}
|
|
||||||
{% load form_helpers %}
|
|
||||||
|
|
||||||
<h4>{% trans "Deployment Roles" %}</h4>
|
|
||||||
<form method="POST" action="." class="deployment-roles-form">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% include 'horizon/common/_form_errors.html' with form=form %}
|
|
||||||
{% for role in roles %}
|
|
||||||
<div class="form-group well well-sm clearfix{% if field.errors %} error{% endif %} {{ field.css_classes }}">
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{{ role.field|add_bootstrap_class }}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<a
|
|
||||||
href="{% url "horizon:infrastructure:roles:detail" role_id=role.id %}"
|
|
||||||
class="deployment-roles-label"
|
|
||||||
>{{ role.name }}</a>
|
|
||||||
{% for error in role.field.errors %}
|
|
||||||
<span class="help-block"><span class="text-danger">
|
|
||||||
{{ error }}
|
|
||||||
</span></span>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
<hr>
|
|
||||||
<button type="submit" class="btn btn-default">
|
|
||||||
<i class="fa fa-save"></i>
|
|
||||||
{% trans "Save changes" %}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
@ -1,28 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
{% load url from future %}
|
|
||||||
|
|
||||||
<h4>{% trans "Deployment Roles" %}</h4>
|
|
||||||
{% 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="col-sm-2">
|
|
||||||
{% if role.deployed_node_count < role.planned_node_count %}
|
|
||||||
<strong>{{ role.deployed_node_count }}</strong><small class="text-muted">/{{ role.planned_node_count }}</small>
|
|
||||||
{% else %}
|
|
||||||
<strong>{{ role.planned_node_count }}</strong>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<a
|
|
||||||
href="{% url "horizon:infrastructure:roles:detail" role_id=role.id %}"
|
|
||||||
>{{ role.name }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'infrastructure/base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Undeploy overcloud" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Undeploy overcloud") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block infrastructure_main %}
|
|
||||||
{% include "infrastructure/overview/_undeploy_confirmation.html" %}
|
|
||||||
{% endblock %}
|
|
@ -15,12 +15,14 @@
|
|||||||
from django.conf import urls
|
from django.conf import urls
|
||||||
|
|
||||||
from tuskar_ui.infrastructure.overview import views
|
from tuskar_ui.infrastructure.overview import views
|
||||||
import tuskar_boxes.views
|
import tuskar_boxes.overview.views as boxes_views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = urls.patterns(
|
urlpatterns = urls.patterns(
|
||||||
'',
|
'',
|
||||||
urls.url(r'^$', tuskar_boxes.views.IndexView.as_view(), name='index'),
|
urls.url(r'^$',
|
||||||
|
boxes_views.IndexView.as_view(),
|
||||||
|
name='index'),
|
||||||
urls.url(r'^deploy-confirmation$',
|
urls.url(r'^deploy-confirmation$',
|
||||||
views.DeployConfirmationView.as_view(),
|
views.DeployConfirmationView.as_view(),
|
||||||
name='deploy_confirmation'),
|
name='deploy_confirmation'),
|
||||||
|
@ -12,7 +12,40 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from tuskar_ui import api
|
||||||
from tuskar_ui.infrastructure.overview import views
|
from tuskar_ui.infrastructure.overview import views
|
||||||
|
|
||||||
|
|
||||||
|
def flavor_nodes(request, flavor):
|
||||||
|
"""Lists all nodes that match the given flavor exactly."""
|
||||||
|
for node in api.node.Node.list(request):
|
||||||
|
if all([
|
||||||
|
int(node.cpus) == int(flavor.vcpus),
|
||||||
|
int(node.memory_mb) == int(flavor.ram),
|
||||||
|
int(node.local_gb) == int(flavor.disk),
|
||||||
|
# TODO(rdopieralski) add architecture when available
|
||||||
|
]):
|
||||||
|
yield node
|
||||||
|
|
||||||
class IndexView(views.IndexView):
|
class IndexView(views.IndexView):
|
||||||
pass
|
template_name = "tuskar_boxes/overview/index.html"
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
context = super(IndexView, self).get_context_data(*args, **kwargs)
|
||||||
|
flavors = api.flavor.Flavor.list(self.request)
|
||||||
|
flavors.sort(key=lambda np: (np.vcpus, np.ram, np.disk))
|
||||||
|
context['flavors'] = []
|
||||||
|
for flavor in flavors:
|
||||||
|
nodes = [{
|
||||||
|
'role': '',
|
||||||
|
} for node in flavor_nodes(self.request, flavor)]
|
||||||
|
flavor = {
|
||||||
|
'name': flavor.name,
|
||||||
|
'vcpus': flavor.vcpus,
|
||||||
|
'ram': flavor.ram,
|
||||||
|
'disk': flavor.disk,
|
||||||
|
'nodes': nodes,
|
||||||
|
}
|
||||||
|
if nodes: # Don't list empty flavors
|
||||||
|
context['flavors'].append(flavor)
|
||||||
|
return context
|
||||||
|
@ -4,13 +4,6 @@
|
|||||||
|
|
||||||
{% block title %}{% trans 'My OpenStack Deployment' %}{% endblock %}
|
{% 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 %}
|
{% block page_header %}
|
||||||
{% include 'horizon/common/_domain_page_header.html' with title=_('My OpenStack Deployment') %}
|
{% include 'horizon/common/_domain_page_header.html' with title=_('My OpenStack Deployment') %}
|
||||||
{% endblock page_header %}
|
{% endblock page_header %}
|
||||||
@ -36,7 +29,7 @@
|
|||||||
{% if stack %}
|
{% if stack %}
|
||||||
{% include "infrastructure/overview/role_nodes_status.html" %}
|
{% include "infrastructure/overview/role_nodes_status.html" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% include "infrastructure/overview/role_nodes_edit.html" %}
|
{% include "tuskar_boxes/overview/role_nodes_edit.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,205 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
{% load form_helpers %}
|
||||||
|
|
||||||
|
<h4>{% trans "Available Deployment Roles" %}</h4>
|
||||||
|
<form method="POST" action="." class="boxes-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% include 'horizon/common/_form_errors.html' with form=form %}
|
||||||
|
|
||||||
|
<div class="boxes-available-roles">
|
||||||
|
{% for role in roles %}{% spaceless %}
|
||||||
|
<div class="boxes-role-{{ role.name|slugify }} boxes-role" data-name="{{ role.name|slugify }}">
|
||||||
|
{{ role.field|add_bootstrap_class }}
|
||||||
|
{{ role.name|title }}
|
||||||
|
</div>
|
||||||
|
{% endspaceless %}{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>{% trans "Available Node Profiles" %}</h4>
|
||||||
|
{% for flavor in flavors %}
|
||||||
|
<div class="boxes-flavor">
|
||||||
|
<p>
|
||||||
|
<strong>Node Profile:</strong>
|
||||||
|
<i>{{ flavor.name }}</i>
|
||||||
|
{{ flavor.vcpus }} CPU,
|
||||||
|
{{ flavor.ram }}MB RAM,
|
||||||
|
{{ flavor.disk }}GB Disk
|
||||||
|
</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<div class="boxes-drop-roles">
|
||||||
|
</div>
|
||||||
|
<div class="boxes-drop">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-7 boxes-nodes">
|
||||||
|
{% for node in flavor.nodes %}{% spaceless %}
|
||||||
|
<div class="boxes-node">free</div>
|
||||||
|
{% endspaceless %}{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<button type="submit" class="btn btn-default">
|
||||||
|
<i class="fa fa-save"></i>
|
||||||
|
{% trans "Save changes" %}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(window.$ || window.addHorizonLoadEvent)(function () {
|
||||||
|
function get_role_counts($flavor) {
|
||||||
|
var roles = {};
|
||||||
|
$flavor.find('div.boxes-drop-roles div.boxes-role').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = $this.data('name');
|
||||||
|
var count = +$this.find('input.number-picker').val();
|
||||||
|
roles[name] = count;
|
||||||
|
});
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_boxes() {
|
||||||
|
$('div.boxes-flavor').each(function () {
|
||||||
|
var $flavor = $(this);
|
||||||
|
var roles = get_role_counts($flavor);
|
||||||
|
var role_names = Object.getOwnPropertyNames(roles);
|
||||||
|
var count = 0;
|
||||||
|
var role = 0;
|
||||||
|
$flavor.find('div.boxes-nodes div.boxes-node').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
$this.removeClass('boxes-role-controller boxes-role-compute boxes-role-block-storage boxes-role-object-storage');
|
||||||
|
while (count >= roles[role_names[role]]) {
|
||||||
|
role += 1;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
if (!role_names[role]) {
|
||||||
|
$(this).html('free');
|
||||||
|
} else {
|
||||||
|
$this.addClass('boxes-role-' + role_names[role]).html(' ');
|
||||||
|
}
|
||||||
|
count += 1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('div.boxes-role').draggable({
|
||||||
|
revert: 'invalid',
|
||||||
|
helper: 'clone',
|
||||||
|
stack: '.boxes-roles',
|
||||||
|
opacity: 0.5
|
||||||
|
});
|
||||||
|
$('div.boxes-drop').droppable({
|
||||||
|
accept: 'div.boxes-role',
|
||||||
|
activeClass: 'boxes-drop-active',
|
||||||
|
hoverClass: 'boxes-drop-hover',
|
||||||
|
tolerance: 'touch',
|
||||||
|
drop: function (ev, ui) {
|
||||||
|
ui.draggable.appendTo($(this).prev('.boxes-drop-roles'));
|
||||||
|
ui.draggable.find('input.number-picker').val(1);
|
||||||
|
window.setTimeout(update_boxes, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('div.boxes-available-roles').droppable({
|
||||||
|
accept: 'div.boxes-role',
|
||||||
|
activeClass: 'boxes-drop-active',
|
||||||
|
hoverClass: 'boxes-drop-hover',
|
||||||
|
tolerance: 'touch',
|
||||||
|
drop: function (ev, ui) {
|
||||||
|
ui.draggable.appendTo(this);
|
||||||
|
ui.draggable.find('input.number-picker').val(0);
|
||||||
|
window.setTimeout(update_boxes, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
update_boxes();
|
||||||
|
$('input.number-picker').change(update_boxes);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
.boxes-node {
|
||||||
|
display: inline-block;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #999;
|
||||||
|
background: #eee;
|
||||||
|
margin: 0 4px 4px 0;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
padding: 20px 4px 0 4px;
|
||||||
|
}
|
||||||
|
.boxes-available-roles {
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #eee;
|
||||||
|
border: 1px dashed #666;
|
||||||
|
min-height: 42px;
|
||||||
|
min-width: 120px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 0 0 4px;
|
||||||
|
}
|
||||||
|
.boxes-role {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px solid;
|
||||||
|
width: 180px;
|
||||||
|
cursor: move;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 0 4px 4px 0;
|
||||||
|
background-color: #fce94f;
|
||||||
|
border-color: #edd400;
|
||||||
|
color: #c4a000;
|
||||||
|
}
|
||||||
|
.boxes-available-roles .boxes-role {
|
||||||
|
text-align: center;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
.boxes-available-roles .boxes-role .form-control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.boxes-role-controller {
|
||||||
|
background-color: #fcaf3e;
|
||||||
|
border-color: #f57900;
|
||||||
|
color: #ce5c00;
|
||||||
|
}
|
||||||
|
.boxes-role-compute {
|
||||||
|
background-color: #8ae234;
|
||||||
|
border-color: #73d216;
|
||||||
|
color: #4e9a06;
|
||||||
|
}
|
||||||
|
.boxes-role-object-storage {
|
||||||
|
background-color: #729fcf;
|
||||||
|
border-color: #3465a4;
|
||||||
|
color: #204a87;
|
||||||
|
}
|
||||||
|
.boxes-role-block-storage {
|
||||||
|
background-color: #ad7fa8;
|
||||||
|
border-color: #75507b;
|
||||||
|
color: #5c3566;
|
||||||
|
}
|
||||||
|
.boxes-drop {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px;
|
||||||
|
border: 1px dashed;
|
||||||
|
width: 180px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #eee;
|
||||||
|
border-color: #666;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
.boxes-drop-active {
|
||||||
|
background-color: #ccc;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
.boxes-drop-hover {
|
||||||
|
background-color: #999;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user