Add angular server groups panel
This patch adds angular server groups panel under the project->compute panel group. To be added in subsequent patches: - Create Action - Delete Action - Detais To view the server groups panel only the 'ServerGroups' nova API extension is available. Change-Id: Ide9f54439c52cce9642c2dd417f9e7a8ad98e846 Implements: blueprint ng-server-groups
This commit is contained in:
parent
a17a81aece
commit
ce283b4a31
@ -30,7 +30,8 @@ MICROVERSION_FEATURES = {
|
||||
"nova": {
|
||||
"locked_attribute": ["2.9", "2.42"],
|
||||
"instance_description": ["2.19", "2.42"],
|
||||
"remote_console_mks": ["2.8", "2.53"]
|
||||
"remote_console_mks": ["2.8", "2.53"],
|
||||
"servergroup_soft_policies": ["2.15", "2.60"]
|
||||
},
|
||||
"cinder": {
|
||||
"consistency_groups": ["2.0", "3.10"],
|
||||
|
@ -0,0 +1,41 @@
|
||||
# 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 logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServerGroups(horizon.Panel):
|
||||
name = _("Server Groups")
|
||||
slug = "server_groups"
|
||||
permissions = ('openstack.services.compute',)
|
||||
policy_rules = (("compute", "os_compute_api:os-server-groups:index"),)
|
||||
|
||||
def allowed(self, context):
|
||||
request = context['request']
|
||||
try:
|
||||
return (
|
||||
super(ServerGroups, self).allowed(context)
|
||||
and request.user.has_perms(self.permissions)
|
||||
)
|
||||
except Exception:
|
||||
LOG.exception("Call to list enabled services failed. This is "
|
||||
"likely due to a problem communicating with the "
|
||||
"Nova endpoint. Server Groups panel will not be "
|
||||
"displayed.")
|
||||
return False
|
22
openstack_dashboard/dashboards/project/server_groups/urls.py
Normal file
22
openstack_dashboard/dashboards/project/server_groups/urls.py
Normal file
@ -0,0 +1,22 @@
|
||||
# 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 url
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon.browsers import views
|
||||
|
||||
|
||||
title = _("Server Groups")
|
||||
urlpatterns = [
|
||||
url(r'^$', views.AngularIndexView.as_view(title=title), name='index'),
|
||||
]
|
@ -0,0 +1,10 @@
|
||||
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||
PANEL = 'server_groups'
|
||||
# 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 = 'compute'
|
||||
|
||||
# Python panel class of the PANEL to be added.
|
||||
ADD_PANEL = ('openstack_dashboard.dashboards.project.server_groups'
|
||||
'.panel.ServerGroups')
|
@ -40,6 +40,7 @@
|
||||
'horizon.app.core.metadata',
|
||||
'horizon.app.core.network_qos',
|
||||
'horizon.app.core.openstack-service-api',
|
||||
'horizon.app.core.server_groups',
|
||||
'horizon.app.core.trunks',
|
||||
'horizon.app.core.workflow',
|
||||
'horizon.framework.conf',
|
||||
|
@ -296,6 +296,12 @@
|
||||
"path": "/api/nova/servers/",
|
||||
"error": "Unable to retrieve instances."
|
||||
},
|
||||
{
|
||||
"func": 'getServerGroups',
|
||||
"method": 'get',
|
||||
"path": '/api/nova/servergroups/',
|
||||
"error": 'Unable to retrieve server groups.'
|
||||
},
|
||||
{
|
||||
"func": "getExtensions",
|
||||
"method": "get",
|
||||
|
@ -0,0 +1,3 @@
|
||||
<hz-resource-panel resource-type-name="OS::Nova::ServerGroup">
|
||||
<hz-resource-table resource-type-name="OS::Nova::ServerGroup"></hz-resource-table>
|
||||
</hz-resource-panel>
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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
|
||||
* @ngname horizon.app.core.server_groups
|
||||
*
|
||||
* @description
|
||||
* Provides all of the services and widgets required
|
||||
* to support and display server groups related content.
|
||||
*/
|
||||
angular
|
||||
.module('horizon.app.core.server_groups', [
|
||||
'horizon.framework.conf',
|
||||
'horizon.app.core'
|
||||
])
|
||||
.constant('horizon.app.core.server_groups.resourceType', 'OS::Nova::ServerGroup')
|
||||
.run(run)
|
||||
.config(config);
|
||||
|
||||
run.$inject = [
|
||||
'horizon.app.core.server_groups.resourceType',
|
||||
'horizon.app.core.server_groups.service',
|
||||
'horizon.framework.conf.resource-type-registry.service'
|
||||
];
|
||||
|
||||
function run(serverGroupResourceType,
|
||||
serverGroupsService,
|
||||
registry) {
|
||||
registry.getResourceType(serverGroupResourceType)
|
||||
.setNames(gettext('Server Group'), gettext('Server Groups'))
|
||||
.setProperties(serverGroupProperties())
|
||||
.setListFunction(serverGroupsService.getServerGroupsPromise)
|
||||
.tableColumns
|
||||
.append({
|
||||
id: 'name',
|
||||
priority: 1,
|
||||
sortDefault: true
|
||||
})
|
||||
// The name is not unique, so we need to show the ID to
|
||||
// distinguish.
|
||||
.append({
|
||||
id: 'id',
|
||||
priority: 1
|
||||
})
|
||||
.append({
|
||||
id: 'policy',
|
||||
priority: 1
|
||||
});
|
||||
|
||||
registry.getResourceType(serverGroupResourceType).filterFacets
|
||||
.append({
|
||||
label: gettext('Name'),
|
||||
name: 'name',
|
||||
singleton: true
|
||||
})
|
||||
.append({
|
||||
label: gettext('ID'),
|
||||
name: 'id',
|
||||
singleton: true
|
||||
})
|
||||
.append({
|
||||
label: gettext('Policy'),
|
||||
name: 'policy',
|
||||
singleton: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name serverGroupProperties
|
||||
* @description resource properties for server group module
|
||||
*/
|
||||
function serverGroupProperties() {
|
||||
return {
|
||||
name: gettext('Name'),
|
||||
id: gettext('ID'),
|
||||
policy: gettext('Policy')
|
||||
};
|
||||
}
|
||||
|
||||
config.$inject = [
|
||||
'$windowProvider',
|
||||
'$routeProvider'
|
||||
];
|
||||
|
||||
/**
|
||||
* @name config
|
||||
* @param {Object} $windowProvider
|
||||
* @param {Object} $routeProvider
|
||||
* @description Routes used by this module.
|
||||
* @returns {undefined} Returns nothing
|
||||
*/
|
||||
function config($windowProvider, $routeProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'app/core/server_groups/';
|
||||
|
||||
$routeProvider.when('/project/server_groups', {
|
||||
templateUrl: path + 'panel.html'
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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('horizon.app.core.server_groups', function () {
|
||||
it('should exist', function () {
|
||||
expect(angular.module('horizon.app.core.server_groups')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('loading the module', function () {
|
||||
var registry;
|
||||
|
||||
beforeEach(module('horizon.app.core.server_groups'));
|
||||
beforeEach(inject(function($injector) {
|
||||
registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
|
||||
}));
|
||||
|
||||
it('registers names', function() {
|
||||
expect(registry.getResourceType('OS::Nova::ServerGroup').getName()).toBe("Server Groups");
|
||||
});
|
||||
|
||||
it('should set facets for search', function () {
|
||||
var names = registry.getResourceType('OS::Nova::ServerGroup').filterFacets
|
||||
.map(getName);
|
||||
expect(names).toContain('name');
|
||||
expect(names).toContain('id');
|
||||
expect(names).toContain('policy');
|
||||
|
||||
function getName(x) {
|
||||
return x.name;
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.server_groups')
|
||||
.factory('horizon.app.core.server_groups.service', serverGroupsService);
|
||||
|
||||
serverGroupsService.$inject = [
|
||||
'horizon.app.core.openstack-service-api.nova'
|
||||
];
|
||||
|
||||
/*
|
||||
* @ngdoc factory
|
||||
* @name horizon.app.core.server_groups.service
|
||||
*
|
||||
* @description
|
||||
* This service provides functions that are used through the Server Groups
|
||||
* features. These are primarily used in the module registrations
|
||||
* but do not need to be restricted to such use. Each exposed function
|
||||
* is documented below.
|
||||
*/
|
||||
function serverGroupsService(nova) {
|
||||
return {
|
||||
getServerGroupsPromise: getServerGroupsPromise
|
||||
};
|
||||
|
||||
/*
|
||||
* @ngdoc function
|
||||
* @name getServerGroupPolicies
|
||||
* @description
|
||||
* Returns a list for the server group policies.
|
||||
*/
|
||||
function getServerGroupPolicies() {
|
||||
return nova.isFeatureSupported('servergroup_soft_policies')
|
||||
.then(isSoftPoliciesSupported);
|
||||
|
||||
function isSoftPoliciesSupported(response) {
|
||||
var policies = {
|
||||
'affinity': gettext('Affinity'),
|
||||
'anti-affinity': gettext('Anti Affinity')
|
||||
};
|
||||
if (response.data) {
|
||||
policies['soft-anti-affinity'] = gettext('Soft Anti Affinity');
|
||||
policies['soft-affinity'] = gettext('Soft Affinity');
|
||||
}
|
||||
return policies;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @ngdoc function
|
||||
* @name getServerGroupsPromise
|
||||
* @description
|
||||
* Rreturns a promise for the matching server groups.
|
||||
* This is used in displaying lists of Server Groups.
|
||||
*/
|
||||
function getServerGroupsPromise() {
|
||||
return nova.getServerGroups().then(modifyResponse);
|
||||
|
||||
function modifyResponse(response) {
|
||||
return getServerGroupPolicies().then(modifyItems);
|
||||
|
||||
function modifyItems(policies) {
|
||||
response.data.items.map(function (item) {
|
||||
// When creating a server group, the back-end limit
|
||||
// server group can only have one policy.
|
||||
item.policy = policies[item.policies[0]];
|
||||
});
|
||||
return {data: {items: response.data.items}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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('server groups service', function() {
|
||||
var $q, $timeout, nova, service;
|
||||
|
||||
beforeEach(module('horizon.app.core.server_groups'));
|
||||
beforeEach(inject(function($injector) {
|
||||
$q = $injector.get('$q');
|
||||
$timeout = $injector.get('$timeout');
|
||||
nova = $injector.get('horizon.app.core.openstack-service-api.nova');
|
||||
service = $injector.get('horizon.app.core.server_groups.service');
|
||||
}));
|
||||
|
||||
describe('getServerGroupsPromise', function() {
|
||||
it("provides a promise when soft policies are supported", inject(function() {
|
||||
var deferred = $q.defer();
|
||||
var deferredPolicies = $q.defer();
|
||||
spyOn(nova, 'getServerGroups').and.returnValue(deferred.promise);
|
||||
spyOn(nova, 'isFeatureSupported').and.returnValue(deferredPolicies.promise);
|
||||
var result = service.getServerGroupsPromise({});
|
||||
deferred.resolve({data: {items: [{id: '1', policies: ['affinity']}]}});
|
||||
deferredPolicies.resolve({data: true});
|
||||
$timeout.flush();
|
||||
|
||||
expect(nova.getServerGroups).toHaveBeenCalled();
|
||||
expect(nova.isFeatureSupported).toHaveBeenCalled();
|
||||
expect(result.$$state.value.data.items[0].id).toBe('1');
|
||||
}));
|
||||
|
||||
it("provides a promise when soft policies are not supported", inject(function() {
|
||||
var deferred = $q.defer();
|
||||
var deferredPolicies = $q.defer();
|
||||
spyOn(nova, 'getServerGroups').and.returnValue(deferred.promise);
|
||||
spyOn(nova, 'isFeatureSupported').and.returnValue(deferredPolicies.promise);
|
||||
var result = service.getServerGroupsPromise({});
|
||||
deferred.resolve({data: {items: [{id: '1', policies: ['affinity']}]}});
|
||||
deferredPolicies.resolve({data: false});
|
||||
$timeout.flush();
|
||||
|
||||
expect(nova.getServerGroups).toHaveBeenCalled();
|
||||
expect(nova.isFeatureSupported).toHaveBeenCalled();
|
||||
expect(result.$$state.value.data.items[0].id).toBe('1');
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
@ -302,6 +302,11 @@ TEST_GLOBAL_MOCKS_ON_PANELS = {
|
||||
'.domains.panel.Domains.can_access'),
|
||||
'return_value': True,
|
||||
},
|
||||
'server_groups': {
|
||||
'method': ('openstack_dashboard.dashboards.project'
|
||||
'.server_groups.panel.ServerGroups.can_access'),
|
||||
'return_value': True,
|
||||
},
|
||||
'trunk-project': {
|
||||
'method': ('openstack_dashboard.dashboards.project'
|
||||
'.trunks.panel.Trunks.can_access'),
|
||||
|
@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
[`blueprint ng-server-groups <https://blueprints.launchpad.net/horizon/+spec/ng-server-groups>`_]
|
||||
This blueprint add angular server groups panel below the
|
||||
Project->Compute panel group. The panel turns on if Nova API
|
||||
extension 'ServerGroups' is available. It displays information about
|
||||
server groups.
|
Loading…
Reference in New Issue
Block a user