Commit 75fc881f authored by Justin Pomeroy's avatar Justin Pomeroy

Add angular Load Balancers V2 panel

This adds an angular version of the Load Balancers V2 panel,
including the Load Balancers table and config to get karma working.
The karma config assumes the horizon directory is a sibling of
neutron-lbaas-dashboard.

To use, copy the _1481_project_ng_loadbalancersv2_panel.py file from
neutron_lbaas_dashboard/enabled into openstack_dashboard/enabled.

Partially-Implements: blueprint horizon-lbaas-v2-ui
Change-Id: I99c4ec705433385c19256c887944706472642a25
parent 2d5f4a29
......@@ -28,6 +28,8 @@ pip-log.txt
nosetests.xml
.testrepository
.venv
node_modules
coverage*
# Translations
*.mo
......
# -*- 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
......@@ -14,6 +12,9 @@
import pbr.version
# Register the REST API URLs so they can be called from the JavaScript files
import neutron_lbaas_dashboard.api.rest # noqa
__version__ = pbr.version.VersionInfo(
'neutron_lbaas_dashboard').version_string()
# 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 neutron_lbaas_dashboard.api.rest import lbaasv2 # noqa
# 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.
"""API over the neutron LBaaS v2 service.
"""
from django.views import generic
from openstack_dashboard.api import neutron
from openstack_dashboard.api.rest import urls
from openstack_dashboard.api.rest import utils as rest_utils
neutronclient = neutron.neutronclient
@urls.register
class LoadBalancers(generic.View):
"""API for load balancers.
"""
url_regex = r'lbaas/loadbalancers/$'
@rest_utils.ajax()
def get(self, request):
"""List load balancers for current project.
The listing result is an object with property "items".
"""
tenant_id = request.user.project_id
result = neutronclient(request).list_loadbalancers(tenant_id=tenant_id)
return {'items': result.get('loadbalancers')}
# (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.utils.translation import ugettext_lazy as _
import horizon
class NGLoadBalancers(horizon.Panel):
name = _("Load Balancers")
slug = 'ngloadbalancersv2'
permissions = ('openstack.services.network',)
def allowed(self, context):
# TODO(jpomero) temporarily enabling panel for any user
# request = context['request']
# if not request.user.has_perms(self.permissions):
# return False
# try:
# if not neutron.is_service_enabled(request,
# config_name='enable_lb',
# ext_name='lbaas'):
# return False
# except Exception:
# LOG.error("Call to list enabled services failed. This is likely "
# "due to a problem communicating with the Neutron "
# "endpoint. Load Balancers panel will not be displayed")
# return False
# if not super(LoadBalancer, self).allowed(context):
# return False
return True
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Load Balancers" %}{% endblock %}
{% block page_header %}
<hz-page-header header="'{% trans "Load Balancers" %}'"></hz-page-header>
{% endblock page_header %}
{% block main %}
<ng-include src="'{{ STATIC_URL }}dashboard/project/lbaasv2/loadbalancers/table.html'"></ng-include>
{% endblock %}
# (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.conf.urls import patterns
from django.conf.urls import url
from neutron_lbaas_dashboard.dashboards.project.ngloadbalancersv2 import views
urlpatterns = patterns(
'neutron_lbaas_dashboard.dashboards.project.ngloadbalancersv2.views',
url(r'^$', views.IndexView.as_view(), name='index'),
)
# (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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
class IndexView(generic.TemplateView):
template_name = 'project/ngloadbalancersv2/index.html'
# 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.
# The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'ngloadbalancersv2'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'project'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'network'
# Python panel class of the PANEL to be added.
ADD_PANEL = (
'neutron_lbaas_dashboard.dashboards.project.ngloadbalancersv2.panel'
'.NGLoadBalancers')
ADD_INSTALLED_APPS = ['neutron_lbaas_dashboard']
ADD_ANGULAR_MODULES = ['horizon.dashboard.project.lbaasv2']
# AUTO_DISCOVER_STATIC_FILES = True
ADD_JS_FILES = [
'app/core/openstack-service-api/lbaasv2.service.js',
'dashboard/project/lbaasv2/lbaasv2.module.js',
'dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.js',
'dashboard/project/lbaasv2/loadbalancers/table.controller.js',
'dashboard/project/lbaasv2/loadbalancers/filters.js',
]
ADD_JS_SPEC_FILES = [
'app/core/openstack-service-api/lbaasv2.service.spec.js',
'dashboard/project/lbaasv2/lbaasv2.module.spec.js',
'dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.spec.js',
'dashboard/project/lbaasv2/loadbalancers/table.controller.spec.js',
'dashboard/project/lbaasv2/loadbalancers/filters.spec.js',
]
#
# ADD_SCSS_FILES = [
#
# ]
/*
* 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.
*/
'use strict';
var fs = require('fs');
var path = require('path');
module.exports = function (config) {
var xstaticPath;
var basePaths = [
'../horizon/.venv'
];
for (var i = 0; i < basePaths.length; i++) {
var basePath = path.resolve(basePaths[i]);
if (fs.existsSync(basePath)) {
xstaticPath = basePath + '/lib/python2.7/site-packages/xstatic/pkg/';
break;
}
}
if (!xstaticPath) {
console.error('xStatic libraries not found, please set up venv');
process.exit(1);
}
config.set({
preprocessors: {
// Used to collect templates for preprocessing.
// NOTE: the templates must also be listed in the files section below.
'./static/**/*.html': ['ng-html2js'],
// Used to indicate files requiring coverage reports.
'./static/**/!(*.spec).js': ['coverage'],
},
// Sets up module to process templates.
ngHtml2JsPreprocessor: {
prependPrefix: '/static/',
moduleName: 'templates'
},
// Assumes you're in the top-level horizon directory.
basePath: './',
// Contains both source and test files.
files: [
/*
* shim, partly stolen from /i18n/js/horizon/
* Contains expected items not provided elsewhere (dynamically by
* Django or via jasmine template.
*/
'../../horizon/test-shim.js',
// from jasmine.html
xstaticPath + 'jquery/data/jquery.js',
xstaticPath + 'angular/data/angular.js',
xstaticPath + 'angular/data/angular-mocks.js',
xstaticPath + 'angular/data/angular-cookies.js',
xstaticPath + 'angular_bootstrap/data/angular-bootstrap.js',
xstaticPath + 'angular_gettext/data/angular-gettext.js',
xstaticPath + 'angular/data/angular-sanitize.js',
xstaticPath + 'd3/data/d3.js',
xstaticPath + 'rickshaw/data/rickshaw.js',
xstaticPath + 'angular_smart_table/data/smart-table.js',
xstaticPath + 'angular_lrdragndrop/data/lrdragndrop.js',
xstaticPath + 'spin/data/spin.js',
xstaticPath + 'spin/data/spin.jquery.js',
// TODO: These should be mocked.
'../../horizon/horizon/static/horizon/js/horizon.js',
/**
* Include framework source code from horizon that we need.
* Otherwise, karma will not be able to find them when testing.
* These files should be mocked in the foreseeable future.
*/
'../../horizon/horizon/static/framework/**/*.module.js',
'../../horizon/horizon/static/framework/**/!(*.spec|*.mock).js',
'../../horizon/openstack_dashboard/static/**/*.module.js',
'../../horizon/openstack_dashboard/static/**/!(*.spec|*.mock).js',
'../../horizon/openstack_dashboard/dashboards/**/static/**/*.module.js',
'../../horizon/openstack_dashboard/dashboards/**/static/**/!(*.spec|*.mock).js',
/**
* First, list all the files that defines application's angular modules.
* Those files have extension of `.module.js`. The order among them is
* not significant.
*/
'./static/**/*.module.js',
/**
* Followed by other JavaScript files that defines angular providers
* on the modules defined in files listed above. And they are not mock
* files or spec files defined below. The order among them is not
* significant.
*/
'./static/**/!(*.spec|*.mock).js',
/**
* Then, list files for mocks with `mock.js` extension. The order
* among them should not be significant.
*/
'../../horizon/openstack_dashboard/static/**/*.mock.js',
//'./static/**/*.mock.js',
/**
* Finally, list files for spec with `spec.js` extension. The order
* among them should not be significant.
*/
'./static/**/*.spec.js',
/**
* Angular external templates
*/
'./static/**/*.html'
],
autoWatch: true,
frameworks: ['jasmine'],
browsers: ['PhantomJS'],
phantomjsLauncher: {
// Have phantomjs exit if a ResourceError is encountered
// (useful if karma exits without killing phantom)
exitOnResourceError: true
},
reporters: ['progress', 'coverage', 'threshold'],
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine',
'karma-ng-html2js-preprocessor',
'karma-coverage',
'karma-threshold-reporter'
],
coverageReporter: {
type: 'html',
dir: '../coverage-karma/'
},
// Coverage threshold values.
thresholdReporter: {
statements: 100,
branches: 100,
functions: 100,
lines: 100
}
});
};
/*
* 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.
*/
(function () {
'use strict';
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.lbaasv2', lbaasv2API);
lbaasv2API.$inject = [
'horizon.framework.util.http.service',
'horizon.framework.widgets.toast.service'
];
/**
* @ngdoc service
* @name horizon.app.core.openstack-service-api.loadbalancers
* @description Provides direct pass through to neutron LBaaS v2 with NO abstraction.
*/
function lbaasv2API(apiService, toastService) {
var service = {
getLoadBalancers: getLoadBalancers
};
return service;
///////////////
// Load Balancers
/**
* @name horizon.app.core.openstack-service-api.lbaasv2.getLoadBalancers
* @description
* Get a list of load balancers.
*
* The listing result is an object with property "items". Each item is
* a load balancer.
*/
function getLoadBalancers() {
return apiService.get('/api/lbaas/loadbalancers/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve load balancers.'));
});
}
}
}());
/*
* 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.
*/
(function() {
'use strict';
describe('LBaaS v2 API', function() {
var testCall, service;
var apiService = {};
var toastService = {};
beforeEach(module('horizon.mock.openstack-service-api', function($provide, initServices) {
testCall = initServices($provide, apiService, toastService);
}));
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(inject(['horizon.app.core.openstack-service-api.lbaasv2', function(lbaasv2API) {
service = lbaasv2API;
}]));
it('defines the service', function() {
expect(service).toBeDefined();
});
var tests = [
{
"func": "getLoadBalancers",
"method": "get",
"path": "/api/lbaas/loadbalancers/",
"error": "Unable to retrieve load balancers."
}
];
// Iterate through the defined tests and apply as Jasmine specs.
angular.forEach(tests, function(params) {
it('defines the ' + params.func + ' call properly', function() {
var callParams = [apiService, service, toastService, params];
testCall.apply(this, callParams);
});
});
});
})();
/*
* 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.
*/
(function () {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.project.lbaasv2
* @description
*
* # horizon.dashboard.project.lbaasv2
*
* The LBaaS v2 dashboard's top level module.
*/
angular
.module('horizon.dashboard.project.lbaasv2', [
'horizon.dashboard.project.lbaasv2.loadbalancers'
]);
}());
/*
* 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.
*/
(function () {
'use strict';
describe('LBaaS v2 Module', function () {
it('should be defined', function () {
expect(angular.module('horizon.dashboard.project.lbaasv2')).toBeDefined();
});
});
})();
/*
* 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.
*/
(function () {
'use strict';
angular
.module('horizon.dashboard.project.lbaasv2.loadbalancers')
.filter('operatingStatus', operatingStatusFilter)
.filter('provisioningStatus', provisioningStatusFilter);
operatingStatusFilter.$inject = [
'horizon.framework.util.i18n.gettext'
];
provisioningStatusFilter.$inject = [
'horizon.framework.util.i18n.gettext'
];
/**
* @ngdoc filter
* @name operatingStatusFilter
* @description
* Takes raw load balancer operating status from the API and returns the user friendly status.
*/
function operatingStatusFilter(gettext) {
var statuses = {
'ONLINE': gettext('Online'),
'OFFLINE': gettext('Offline'),
'DEGRADED': gettext('Degraded'),
'ERROR': gettext('Error')
};
return function (input) {
var result = statuses[input];
return angular.isDefined(result) ? result : input;
};
}
/**
* @ngdoc filter
* @name provisioningStatusFilter
* @description
* Takes raw load balancer provisioning status from the API and returns the user friendly status.
*/
function provisioningStatusFilter(gettext) {
var statuses = {
'ACTIVE': gettext('Active'),
'PENDING_CREATE': gettext('Pending Create'),
'PENDING_UPDATE': gettext('Pending Update'),
'PENDING_DELETE': gettext('Pending Delete'),
'ERROR': gettext('Error')
};
return function (input) {
var result = statuses[input];
return angular.isDefined(result) ? result : input;
};
}
}());
/*
* 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.
*/
(function() {
'use strict';
describe('LBaaS v2 Load Balancers Filters', function () {
beforeEach(module('horizon.framework.util.i18n'));
beforeEach(module('horizon.dashboard.project.lbaasv2.loadbalancers'));
describe('operatingStatus', function () {
var operatingStatusFilter;
beforeEach(inject(function (_operatingStatusFilter_) {
operatingStatusFilter = _operatingStatusFilter_;
}));
it('Returns value when key is present', function () {
expect(operatingStatusFilter('ONLINE')).toBe('Online');