Adding tox file for gate testing and some other fixes
- Renaming some labels - Adding title to the cluster page - Also removing some debuging logs - Fix code to pass pep8 - Remove volume size - Display flavor name instead of ID in detail page Change-Id: Ia3351eace341797f48275c94b8bc352fd83791c4
This commit is contained in:
parent
76225d2aae
commit
ab15cbca8d
|
@ -6,4 +6,6 @@ ChangeLog
|
|||
.DS_Store
|
||||
cue_dashboard.egg*
|
||||
build/
|
||||
.tox/
|
||||
.egg/
|
||||
.idea/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
PANEL_GROUP = 'queuesgroup'
|
||||
PANEL_GROUP_NAME = _('Message Queues')
|
||||
PANEL_GROUP_DASHBOARD = 'project'
|
||||
PANEL_GROUP_NAME = _('Messaging')
|
||||
PANEL_GROUP_DASHBOARD = 'project'
|
||||
|
|
|
@ -21,14 +21,14 @@ from cueclient.v1 import client
|
|||
from keystoneclient import session as ksc_session
|
||||
from keystoneclient.auth.identity import v2
|
||||
from collections import namedtuple
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard import api
|
||||
from horizon.utils.memoized import memoized # noqa
|
||||
|
||||
|
||||
@memoized
|
||||
def cueclient(request):
|
||||
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
auth_url = base.url_for(request, 'identity')
|
||||
auth_url = api.base.url_for(request, 'identity')
|
||||
auth = v2.Token(auth_url, request.user.token.id,
|
||||
tenant_id=request.user.tenant_id,
|
||||
tenant_name=request.user.tenant_name)
|
||||
|
@ -50,17 +50,27 @@ def cluster_get(request, cluster_id):
|
|||
return cluster
|
||||
|
||||
|
||||
def cluster_create(request, name, nic, flavor, size, volume_size):
|
||||
return cueclient(request).clusters.create(name, nic,flavor,
|
||||
size, volume_size)
|
||||
def cluster_create(request, name, nic, flavor, size):
|
||||
return cueclient(request).clusters.create(name, nic[0],
|
||||
flavor, size, 0)
|
||||
|
||||
|
||||
def delete_cluster(request, cluster_id):
|
||||
return cueclient(request).clusters.delete(cluster_id)
|
||||
|
||||
|
||||
#todo
|
||||
#This is needed because the cue client returns a dict
|
||||
#instead of a cluster object.
|
||||
def flavor(request, flavor_id):
|
||||
return api.nova.flavor_get(request, flavor_id)
|
||||
|
||||
|
||||
# todo
|
||||
# This is needed because the cue client returns a dict
|
||||
# instead of a cluster object.
|
||||
def _to_cluster_object(cluster_dict):
|
||||
return namedtuple('Cluster', cluster_dict)(**cluster_dict)
|
||||
endpoint = (cluster_dict['end_points'][0] if cluster_dict['end_points']
|
||||
else None)
|
||||
if endpoint:
|
||||
cluster_dict['url'] = "".join((endpoint['type'],
|
||||
'://',
|
||||
endpoint['uri']))
|
||||
return namedtuple('Cluster', cluster_dict)(**cluster_dict)
|
||||
|
|
|
@ -24,4 +24,3 @@ class CuePanel(horizon.Panel):
|
|||
name = _("Clusters")
|
||||
slug = 'queues'
|
||||
permissions = ('openstack.services.message_queue',)
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@ from django.utils.translation import ungettext_lazy
|
|||
from django.utils.translation import ugettext as _
|
||||
from horizon import tables
|
||||
from cuedashboard import api
|
||||
import logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateCluster(tables.LinkAction):
|
||||
|
@ -55,16 +59,23 @@ class DeleteCluster(tables.BatchAction):
|
|||
api.delete_cluster(request, obj_id)
|
||||
|
||||
|
||||
class UpdateRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, cluster_id):
|
||||
return api.cluster_get(request, cluster_id)
|
||||
|
||||
|
||||
class ClusterTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
verbose_name=_("Name"),
|
||||
link='horizon:project:queues:detail')
|
||||
size = tables.Column("size", verbose_name=_("Size"),)
|
||||
flavor = tables.Column("flavor", verbose_name=_("Flavor"),)
|
||||
size = tables.Column("size", verbose_name=_("Cluster Size"),)
|
||||
status = tables.Column("status", verbose_name=_("Status"))
|
||||
|
||||
class Meta:
|
||||
name = "clusters"
|
||||
verbose_name = _("Clusters")
|
||||
row_class = UpdateRow
|
||||
table_actions = (CreateCluster, DeleteCluster,)
|
||||
row_actions = (DeleteCluster,)
|
||||
|
|
|
@ -14,4 +14,4 @@ class OverviewTab(tabs.Tab):
|
|||
class ClusterDetailTabs(tabs.TabGroup):
|
||||
slug = "cluster_details"
|
||||
tabs = (OverviewTab,)
|
||||
sticky = True
|
||||
sticky = True
|
||||
|
|
|
@ -26,6 +26,8 @@ CLUSTERS = r'^(?P<cluster_id>[^/]+)/%s$'
|
|||
urlpatterns = patterns('',
|
||||
url(r'^$', views.IndexView.as_view(),
|
||||
name='index'),
|
||||
url(CLUSTERS % '', views.DetailView.as_view(), name='detail'),
|
||||
url(r'^create$', views.CreateClusterView.as_view(), name='create'),
|
||||
)
|
||||
url(CLUSTERS % '', views.DetailView.as_view(),
|
||||
name='detail'),
|
||||
url(r'^create$', views.CreateClusterView.as_view(),
|
||||
name='create'),
|
||||
)
|
||||
|
|
|
@ -36,6 +36,7 @@ LOG = logging.getLogger(__name__)
|
|||
class IndexView(tables.DataTableView):
|
||||
table_class = ClusterTable
|
||||
template_name = 'queues/index.html'
|
||||
page_title = _("Clusters")
|
||||
|
||||
def get_data(self):
|
||||
return api.clusters_list(self.request)
|
||||
|
@ -57,6 +58,8 @@ class DetailView(horizon_tabs.TabbedTableView):
|
|||
cluster = self.get_data()
|
||||
table = ClusterTable(self.request)
|
||||
context["cluster"] = cluster
|
||||
flavor = api.flavor(self.request, cluster.flavor)
|
||||
context["flavor"] = flavor.name
|
||||
context["url"] = self.get_redirect_url()
|
||||
context["actions"] = table.render_row_actions(cluster)
|
||||
return context
|
||||
|
@ -66,16 +69,17 @@ class DetailView(horizon_tabs.TabbedTableView):
|
|||
|
||||
cluster_id = self.kwargs['cluster_id']
|
||||
cluster = api.cluster_get(self.request, cluster_id)
|
||||
LOG.info('hlahaha')
|
||||
LOG.info(cluster)
|
||||
LOG.info(type(cluster))
|
||||
return cluster
|
||||
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
cluster = self.get_data()
|
||||
return self.tab_group_class(request, cluster=cluster, **kwargs)
|
||||
# Get flavor name
|
||||
flavor = api.flavor(self.request, cluster.flavor)
|
||||
return self.tab_group_class(request,
|
||||
cluster=flavor,
|
||||
flavor=flavor.name,
|
||||
**kwargs)
|
||||
|
||||
@staticmethod
|
||||
def get_redirect_url():
|
||||
return reverse('horizon:project:queues:index')
|
||||
return reverse('horizon:project:queues:index')
|
||||
|
|
|
@ -36,20 +36,15 @@ class SetInstanceDetailsAction(workflows.Action):
|
|||
name = forms.CharField(max_length=80, label=_("Cluster Name"))
|
||||
flavor = forms.ChoiceField(label=_("Flavor"),
|
||||
help_text=_("Size of image to launch."))
|
||||
size = forms.IntegerField(label=_("Size"),
|
||||
min_value=0,
|
||||
initial=1,
|
||||
help_text=_("Size of cluster."))
|
||||
volume = forms.IntegerField(label=_("Volume Size"),
|
||||
min_value=0,
|
||||
initial=1,
|
||||
help_text=_("Size of the volume in GB."))
|
||||
size = forms.IntegerField(label=_("Cluster Size"),
|
||||
min_value=1,
|
||||
initial=1,
|
||||
help_text=_("Size of cluster."))
|
||||
|
||||
class Meta(object):
|
||||
name = _("Details")
|
||||
help_text_template = "queues/_launch_details_help.html"
|
||||
|
||||
|
||||
@memoized.memoized_method
|
||||
def flavors(self, request):
|
||||
try:
|
||||
|
@ -70,7 +65,7 @@ class SetInstanceDetailsAction(workflows.Action):
|
|||
|
||||
class SetClusterDetails(workflows.Step):
|
||||
action_class = SetInstanceDetailsAction
|
||||
contributes = ("name", "volume", "flavor", "size")
|
||||
contributes = ("name", "flavor", "size")
|
||||
|
||||
|
||||
class SetNetworkAction(workflows.Action):
|
||||
|
@ -94,6 +89,13 @@ class SetNetworkAction(workflows.Action):
|
|||
permissions = ('openstack.services.network',)
|
||||
help_text = _("Select networks for your cluster.")
|
||||
|
||||
def clean(self):
|
||||
# Cue does not currently support attaching multiple networks.
|
||||
if len(self.data.getlist("network", None)) > 1:
|
||||
msg = _("You must select only one network.")
|
||||
self._errors["network"] = self.error_class([msg])
|
||||
return self.cleaned_data
|
||||
|
||||
def populate_network_choices(self, request, context):
|
||||
try:
|
||||
tenant_id = self.request.user.tenant_id
|
||||
|
@ -119,9 +121,9 @@ class SetNetwork(workflows.Step):
|
|||
# contains an empty string, so remove it.
|
||||
networks = [n for n in networks if n != '']
|
||||
if networks:
|
||||
#TODO
|
||||
#Choosing the first networks until Cue
|
||||
#supports more than one networks.
|
||||
# TODO
|
||||
# Choosing the first networks until Cue
|
||||
# supports more than one networks.
|
||||
context['network_id'] = networks[0]
|
||||
|
||||
return context
|
||||
|
@ -140,7 +142,7 @@ class CreateCluster(workflows.Workflow):
|
|||
def __init__(self, request=None, context_seed=None, entry_point=None,
|
||||
*args, **kwargs):
|
||||
super(CreateCluster, self).__init__(request, context_seed,
|
||||
entry_point, *args, **kwargs)
|
||||
entry_point, *args, **kwargs)
|
||||
self.attrs['autocomplete'] = (
|
||||
settings.HORIZON_CONFIG.get('password_autocomplete'))
|
||||
|
||||
|
@ -151,13 +153,13 @@ class CreateCluster(workflows.Workflow):
|
|||
def handle(self, request, context):
|
||||
try:
|
||||
LOG.info("Launching message queue cluster with parameters "
|
||||
"{name=%s, volume=%s, flavor=%s, size=%s, nics=%s}",
|
||||
context['name'], context['volume'], context['flavor'],
|
||||
"{name=%s, flavor=%s, size=%s, nics=%s}",
|
||||
context['name'], context['flavor'],
|
||||
context['size'], context['network_id'])
|
||||
|
||||
cluster_create(request, context['name'], context['network_id'],
|
||||
context['flavor'], context['size'], context['volume'])
|
||||
context['flavor'], context['size'])
|
||||
return True
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
return False
|
||||
return False
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
<dt>{% trans "Network" %}</dt>
|
||||
<dd>{{ cluster.network_id|default:_("-") }}</dd>
|
||||
<dt>{% trans "Flavor" %}</dt>
|
||||
<dd>{{ cluster.flavor|default:_("-") }}</dd>
|
||||
<dt>{% trans "Size" %}</dt>
|
||||
<dd>{{ flavor|default:_("-") }}</dd>
|
||||
<dt>{% trans "Cluster Size" %}</dt>
|
||||
<dd>{{ cluster.size|default:_("-") }}</dd>
|
||||
<dt>{% trans "Volume Size" %}</dt>
|
||||
<dd>{{ cluster.volume_size|default:_("-") }}</dd>
|
||||
<dt>{% trans "Endpoints" %}</dt>
|
||||
<dd>{{ cluster.end_points|default:_("-") }}</dd>
|
||||
<dt>{% trans "Endpoint" %}</dt>
|
||||
<dd>{{ cluster.url|default:_("-") }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{% load i18n %}
|
||||
|
||||
<p>{% blocktrans %}Specify the details for creating a message queue cluster.{% endblocktrans %}</p>
|
||||
<p>{% blocktrans %}<strong>Please note:</strong> The cluster size must be at least 3{% endblocktrans %}</p>
|
|
@ -6,4 +6,5 @@
|
|||
clicking the button, or dragging and dropping. You can change the
|
||||
NIC order by dragging and dropping as well.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</p>
|
||||
<p>{% blocktrans %}<strong>Please note:</strong> You can only choose one network per cluster.{% endblocktrans %}</p>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<table class="table-fixed" id="networkListSortContainer">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="actions">
|
||||
<td class="col-sm-6">
|
||||
<label id="selected_network_label">{% trans "Selected networks" %}</label>
|
||||
<ul id="selected_network" class="networklist">
|
||||
</ul>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<ul id="available_network" class="networklist">
|
||||
</ul>
|
||||
</td>
|
||||
<td class="help_text">
|
||||
<td class="col-sm-6">
|
||||
{% include "queues/_launch_network_help.html" %}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Queues" %}{% endblock %}
|
||||
{% block title %}{% trans "Clusters" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{{ table.render }}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'oslosphinx',
|
||||
]
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'cue-dashboard'
|
||||
copyright = u'2015, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = []
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# -- Options for manual page output -------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = []
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
man_show_urls = True
|
|
@ -0,0 +1 @@
|
|||
.. include:: ../../README.rst
|
|
@ -1,2 +1,2 @@
|
|||
Django>=1.4,<1.7
|
||||
python-cueclient
|
||||
-e git+https://github.com/stackforge/python-cueclient.git#egg=python-cueclient
|
|
@ -0,0 +1,4 @@
|
|||
pep8==1.5.7
|
||||
flake8==2.2.3
|
||||
sphinx>=1.1.2,!=1.2.0,<1.3
|
||||
oslosphinx>=2.2.0 # Apache-2.0
|
|
@ -0,0 +1,25 @@
|
|||
[tox]
|
||||
envlist = pep8
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[flake8]
|
||||
show-source = true
|
||||
ignore = H101,H302,H803
|
||||
builtins = _
|
||||
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools,local_settings.py
|
Loading…
Reference in New Issue