Add queues API and table

Added the API required for the queues panel.
Also added the table to display queues data.

Co-Authored-By: Fei Long Wang <flwang@catalyst.net.nz>
Co-Authored-By: Thai Tran <tqtran@us.ibm.com>
Change-Id: I8cf690ccfb80eb1a64bb6769a61010ac3ced7a90
This commit is contained in:
Thai Tran 2016-02-02 11:24:37 -08:00
parent 549053d5df
commit e19fc3bd54
12 changed files with 482 additions and 3 deletions

View File

@ -0,0 +1,22 @@
# Copyright 2015 IBM Corp.
#
# 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 pbr.version
# Register the REST API URLs so they can be called from the JavaScript files
import zaqar_ui.api.rest # noqa
__version__ = pbr.version.VersionInfo(
'neutron_lbaas_dashboard').version_string()

30
zaqar_ui/api/__init__.py Normal file
View File

@ -0,0 +1,30 @@
# Copyright 2015 IBM Corp.
#
# 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.
"""
Methods and interface objects used to interact with external APIs.
API method calls return objects that are in many cases objects with
attributes that are direct maps to the data returned from the API http call.
Unfortunately, these objects are also often constructed dynamically, making
it difficult to know what data is available from the API object. Because of
this, all API calls should wrap their returned object in one defined here,
using only explicitly defined attributes and/or methods.
In other words, Horizon developers not working on openstack_dashboard.api
shouldn't need to understand the finer details of APIs for
Keystone/Nova/Glance/Swift et. al.
"""
from zaqar_ui.api import zaqar # noqa

View File

@ -0,0 +1,24 @@
# Copyright 2015 IBM Corp.
#
# 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.
"""This package holds the REST API that supports the LBaaS v2 dashboard
Javascript code.
It is not intended to be used outside of Horizon, and makes no promises of
stability or fitness for purpose outside of that scope.
It does not promise to adhere to the general OpenStack API Guidelines set out
in https://wiki.openstack.org/wiki/APIChangeGuidelines.
"""
# import REST API modules here
from zaqar_ui.api.rest import zaqar # noqa

View File

@ -0,0 +1,78 @@
# Copyright 2015 Cisco Systems.
#
# 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.
from django.views import generic
from zaqar_ui.api import zaqar
from openstack_dashboard.api.rest import urls
from openstack_dashboard.api.rest import utils as rest_utils
@urls.register
class Queue(generic.View):
"""API for retrieving a single queue
"""
url_regex = r'zaqar/queues/(?P<queue_name>[^/]+)$'
@rest_utils.ajax()
def get(self, request, queue_name):
"""Get a specific queue
"""
return zaqar.queue_show(request, queue_name).to_dict()
@urls.register
class Queues(generic.View):
"""API for queues
"""
url_regex = r'zaqar/queues/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of the Queues for a project.
The returned result is an object with property 'items' and each
item under this is a queue.
"""
result = zaqar.queue_list(request)
queues = []
for q in result:
stats = q.stats['messages']
queues.append({'name': q.name,
'claimed': stats['claimed'],
'free': stats['free'],
'total': stats['total'],
'metadata': q.metadata()})
return queues
@rest_utils.ajax(data_required=True)
def delete(self, request):
"""Delete one or more queue by name.
Returns HTTP 204 (no content) on successful deletion.
"""
for queue_name in request.DATA:
zaqar.queue_delete(request, queue_name)
@rest_utils.ajax(data_required=True)
def create(self, request):
"""Create a new queue.
Returns the new queue object on success.
"""
new_queue = zaqar.queue_create(request, **request.DATA)
return rest_utils.CreatedResponse(
'/api/messaging/queues/%s' % new_queue.name,
new_queue.to_dict())

93
zaqar_ui/api/zaqar.py Normal file
View File

@ -0,0 +1,93 @@
# Copyright 2015 Catalyst IT Ltd.
#
# 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.
from __future__ import absolute_import
import logging
from zaqarclient.queues import client as zaqar_client
from horizon import exceptions
from horizon.utils.memoized import memoized
from openstack_dashboard.api import base
LOG = logging.getLogger(__name__)
@memoized
def zaqarclient(request):
zaqar_url = ""
service_type = 'messaging'
try:
zaqar_url = base.url_for(request, service_type)
except exceptions.ServiceCatalogException:
LOG.debug('No messaging service is configured.')
return None
LOG.debug('zaqarclient connection created using the token "%s" and url'
'"%s"' % (request.user.token.id, zaqar_url))
opts = {'os_auth_token': request.user.token.id,
'os_auth_url': base.url_for(request, 'identity'),
'os_project_id': request.user.tenant_id,
'os_service_type': service_type}
auth_opts = {'backend': 'keystone',
'options': opts}
conf = {'auth_opts': auth_opts}
return zaqar_client.Client(url=zaqar_url, version=2, conf=conf)
def queue_list(request, limit=None, marker=None):
return zaqarclient(request).queues(limit=limit, marker=marker)
def queue_create(request, queue_name, metadata):
"""Pop up a modal form, which contains several inputbox:
1. queue_name
2. ttl
3. max message size
4. Metadata
"""
queue = zaqarclient(request).queue(queue_name, force_create=True)
queue.metadata(new_meta=metadata)
def queue_delete(request, queue_name):
queue = zaqarclient(request).queue(queue_name, auto_create=False)
queue.delete()
def queue_update(request, queue_name, metadata):
"""Popup a modal form, the queue name is a realonly label or inputbox.
user can change ttl, max message size and metadata
"""
queue = zaqarclient(request).queue(queue_name, auto_create=False)
queue.metadata(new_meta=metadata)
def queue_get(request, queue_name):
return zaqarclient(request).queue(queue_name, auto_create=False)
def queue_subscribe(request, subscriber, ttl=None, options={}):
"""Popup a modal form, user can input subscriber, ttl and options to
subscribe the queue.
subscriber could be an URL or email address.
"""
pass

View File

@ -3,8 +3,9 @@
{% block title %}{% trans "Queues" %}{% endblock %}
{% block page_header %}
<hz-page-header header="{$ 'Queues' | translate $}"></hz-page-header>
<base href="{{ WEBROOT }}" >
{% endblock page_header %}
{% block main %}
<ng-include src="'{{STATIC_URL}}/dashboard/project/queues/table/table.html'"></ng-include>
{% endblock %}

View File

@ -16,7 +16,8 @@ from django.conf import urls
from zaqar_ui.content.queues import views
urlpatterns = urls.patterns(
'',
'zaqar_ui.content.queues',
urls.url(r'^$', views.IndexView.as_view(), name='index'),
)

View File

@ -25,8 +25,19 @@ ADD_ANGULAR_MODULES = [
'horizon.dashboard.project.queues'
]
ADD_JS_FILES = [
'app/core/openstack-service-api/zaqar.service.js',
'dashboard/project/queues/queues.module.js',
'dashboard/project/queues/table/table.controller.js',
]
ADD_JS_SPEC_FILES = [
'dashboard/project/queues/queues.module.spec.js',
'dashboard/project/queues/table/table.controller.spec.js',
]
ADD_SCSS_FILES = [
'dashboard/project/queues/queues.scss'
]
AUTO_DISCOVER_STATIC_FILES = True
# AUTO_DISCOVER_STATIC_FILES = True

View File

@ -0,0 +1,47 @@
/**
* Copyright 2015 Catalyst IT Ltd.
*
* 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.
*/
(function () {
'use strict';
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.zaqar', ZaqarAPI);
ZaqarAPI.$inject = [
'horizon.framework.util.http.service',
'horizon.framework.widgets.toast.service'
];
function ZaqarAPI(apiService, toastService) {
var service = {
getQueues: getQueues
};
return service;
//////////
function getQueues() {
return apiService.get('/api/zaqar/queues/')
.error(function() {
toastService.add('error', gettext('Unable to retrieve the Queues.'));
});
}
}
}());

View File

@ -0,0 +1,60 @@
/**
* 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.
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name queuesTableController
* @ngController
*
* @description
* Controller for the queues table
*/
angular
.module('horizon.dashboard.project.queues')
.controller('horizon.dashboard.project.queues.tableController', queuesTableController);
queuesTableController.$inject = [
'$scope',
'horizon.app.core.openstack-service-api.zaqar'
];
function queuesTableController($scope, zaqar) {
var ctrl = this;
ctrl.iqueues = [];
ctrl.queues = [];
init();
//////////
function init() {
zaqar.getQueues().success(getQueuesSuccess);
}
function getQueuesSuccess(response) {
// TODO: If the response does not contain the id field
// then you must manually add them on the client-side
// the horizon table's checkboxes requires that the id field be present
console.log(response);
ctrl.queues = response;
}
}
})();

View File

@ -0,0 +1,112 @@
<hz-page-header header="{$ 'Queues' | translate $}"></hz-page-header>
<table ng-controller="horizon.dashboard.project.queues.tableController as table"
hz-table ng-cloak
st-table="table.iqueues"
st-safe-src="table.queues"
default-sort="name"
default-sort-reverse="false"
class="table-striped table-rsp table-detail modern">
<thead>
<!--
Table-column-headers:
The headers for the table columns
-->
<tr>
<th class=select-col>
<input type="checkbox" hz-select-all="table.iqueues">
</th>
<th class="expander"></th>
<th class="rsp-p1" st-sort="name" st-sort-default translate>Name</th>
<th class="rsp-p2" st-sort="metadata" translate>Claimed Messages</th>
<th class="rsp-p2" st-sort="metadata" translate>Free Messages</th>
<th class="rsp-p2" st-sort="metadata" translate>Total Messages</th>
</tr>
</thead>
<tbody>
<!--
Table-rows:
This is where we declaratively define the table columns.
Include select-col if you want to select all.
Include expander if you want to inline details.
Include action-col if you want to perform actions.
rsp-p1 rsp-p2 are responsive priority as user resizes window.
-->
<tr ng-repeat-start="q in table.iqueues track by q.name"
nt-class="{'st-selected': checked[q.name]}">
<td class="select-col">
<input type="checkbox"
ng-model="selected[q.name].checked"
hz-select="q">
</td>
<td class="expander">
<span class="fa fa-chevron-right"
hz-expand-detail duration="200"></span>
</td>
<td class="rsp-p1">{$ q.name $}</td>
<td class="rsp-p2">{$ q.claimed $}</td>
<td class="rsp-p2">{$ q.free $}</td>
<td class="rsp-p2">{$ q.total $}</td>
</tr>
<tr ng-repeat-end class="detail-row">
<!--
Table-row-details:
Provides detail view of specific view, with more information than can be
displayed in the table alone.
-->
<td class="detail" colspan="100">
<!--
The responsive columns that disappear typically should reappear here
with the same responsive priority that they disappear.
E.g. table header with rsp-p2 should be here with rsp-alt-p2
The layout should minimize vertical space to reduce scrolling.
-->
<div class="row">
<!-- Important metadata should go here and table header.
It will appear in the table above if there is room, otherwise
it will appear in the drawer when user resizes the window.
-->
<span class="rsp-alt-p2">
<dl class="col-sm-2">
<dt translate>Flavor</dt>
<dd>{$ q.metadata.flavor $}</dd>
</dl>
<dl class="col-sm-2">
<dt translate>Max Message Size</dt>
<dd>{$ q.metadata.max_message_size $}</dd>
</dl>
<dl class="col-sm-2">
<dt translate>Time To Live</dt>
<dd>{$ q.metadata.ttl $}</dd>
</dl>
</span>
<!-- additional unimportant metadata can be place here -->
<dl class="col-sm-2">
<dt translate>Metadata</dt>
<dd>{$ q.metadata $}</dd>
</dl>
</div>
</td>
</tr>
</tbody>
<tfoot>
<td colspan="100">
<span class="display">{$ table.iqueues.length|itemCount $}</span>
<div st-pagination="" st-items-by-page="10" st-displayed-pages="10"></div>
</td>
</tfoot>
</table>