Optimise how to retrieve pull-down options

1. Add separated exception handler
2. Change to call APIs in parallel

Change-Id: I51e53f10706e3e1bb7c7a3307e3f31c1e77a12ce
This commit is contained in:
Xinni Ge 2017-12-12 18:32:57 +09:00
parent be97728d33
commit 4af156c837
13 changed files with 1362 additions and 180 deletions

View File

@ -12,183 +12,268 @@
import json
from functools import wraps
from multiprocessing import pool
from django.conf import settings
from openstack_dashboard import api as dashboard_api
from openstack_dashboard.api.neutron import neutronclient
from heat_dashboard import api
from heat_dashboard import api as heat_api
def get_resources(request):
try:
API_TIMEOUT = settings.API_TIMEOUT
except AttributeError:
API_TIMEOUT = 60
volumes = [
vol.to_dict() for vol in dashboard_api.cinder.volume_list(request)]
volume_snapshots = [
volsnap.to_dict()
for volsnap in dashboard_api.cinder.volume_snapshot_list(request)]
volume_types = [
voltype.to_dict()
for voltype in dashboard_api.cinder.volume_type_list(request)]
volume_backups = [
volbackup.to_dict()
for volbackup in dashboard_api.cinder.volume_backup_list(request)]
try:
API_PARALLEL = settings.API_PARALLEL
except AttributeError:
API_PARALLEL = 2
images = [
img.to_dict()
for img in dashboard_api.glance.image_list_detailed(request)[0]]
neutron_client = neutronclient(request)
floatingips = neutron_client.list_floatingips().get('floatingips')
networks = neutron_client.list_networks().get('networks')
ports = neutron_client.list_ports().get('ports')
security_groups = \
neutron_client.list_security_groups().get('security_groups')
subnets = neutron_client.list_subnets().get('subnets')
routers = neutron_client.list_routers().get('routers')
# qos_policies = neutron_client.list_security_groups().get('ports')
def handle_exception(func):
@wraps(func)
def wrapped(*args, **kwargs):
ret, err = None, None
try:
ret = func(*args, **kwargs)
except Exception as error:
err = error.message
return ret if ret else [], err
return wrapped
availability_zones = \
[az.to_dict()
for az in dashboard_api.nova.availability_zone_list(request)]
flavors = \
[flavor.to_dict()
for flavor in dashboard_api.nova.flavor_list(request)]
instances = \
[server.to_dict()
for server in dashboard_api.nova.server_list(request)[0]]
keypairs = \
[keypair.to_dict()
for keypair in dashboard_api.nova.keypair_list(request)]
opts = {
'user_roles': request.user.roles,
'volumes': volumes,
'volume_snapshots': volume_snapshots,
'volume_types': volume_types,
'volume_backups': volume_backups,
'images': images,
'floatingips': floatingips,
'networks': networks,
'ports': ports,
'security_groups': security_groups,
'subnets': subnets,
'routers': routers,
# 'qos_policies': qos_policies,
'availability_zones': availability_zones,
'flavors': flavors,
'instances': instances,
'keypairs': keypairs,
}
@handle_exception
def get_networks(request):
return dashboard_api.neutron.network_list(request)
return json.dumps(opts)
@handle_exception
def get_subnets(request):
return dashboard_api.neutron.subnet_list(request)
@handle_exception
def get_volume_ids(request):
return [{'id': vol.id,
'name': vol.name if vol.name else '(%s)' % vol.id}
for vol in dashboard_api.cinder.volume_list(request)]
@handle_exception
def get_volume_snapshots(request):
return [{'id': volsnap.id,
'name': volsnap.name if volsnap.name else '(%s)' % volsnap.id[:6]}
for volsnap in dashboard_api.cinder.volume_snapshot_list(request)]
@handle_exception
def get_volume_types(request):
return [{'id': voltype.id,
'name': voltype.name if voltype.name else '(%s)' % voltype.id[:6]}
for voltype in dashboard_api.cinder.volume_type_list(request)]
@handle_exception
def get_volume_backups(request):
return [{'id': volbackup.id,
'name': volbackup.name
if volbackup.name else '(%s)' % volbackup.id[:6]}
for volbackup in dashboard_api.cinder.volume_backup_list(request)]
@handle_exception
def get_images(request):
images = dashboard_api.glance.image_list_detailed(request)
if isinstance(images, tuple):
images = images[0]
return [{'id': img.id,
'name': img.name if img.name else '(%s)' % img.id[:6]}
for img in images]
@handle_exception
def get_floatingips(request):
return [{'id': fip.id, 'name': fip.floating_ip_address}
for fip in dashboard_api.neutron.tenant_floating_ip_list(
request, True)]
@handle_exception
def get_ports(request):
return [{'id': port.id,
'name': port.name if port.name else '(%s)' % port.id[:6]}
for port in dashboard_api.neutron.port_list(request)]
@handle_exception
def get_security_groups(request):
return [{'id': secgroup.id,
'name': secgroup.name
if secgroup.name else '(%s)' % secgroup.id[:6]}
for secgroup in dashboard_api.neutron.security_group_list(request)]
@handle_exception
def get_routers(request):
return [{'id': router.id,
'name': router.name if router.name else '(%s)' % router.id[:6]}
for router in dashboard_api.neutron.router_list(request)]
@handle_exception
def get_qos_policies(request):
return [{'id': policy.id,
'name': policy.name
if policy.name else '(%s)' % policy.id[:6]}
for policy in dashboard_api.neutron.policy_list(request)]
@handle_exception
def get_availability_zones(request):
return [{'id': az.zoneName, 'name': az.zoneName}
for az in dashboard_api.nova.availability_zone_list(request)]
@handle_exception
def get_flavors(request):
return [{'id': flavor.name, 'name': flavor.name}
for flavor in dashboard_api.nova.flavor_list(request)]
@handle_exception
def get_instances(request):
servers = dashboard_api.nova.server_list(request)
if isinstance(servers, tuple):
servers = servers[0]
return [{'id': server.id,
'name': server.name if server.name else '(%s)' % server.id[:6]}
for server in servers]
@handle_exception
def get_keypairs(request):
return [{'name': keypair.name}
for keypair in dashboard_api.nova.keypair_list(request)]
@handle_exception
def get_template_versions(request):
return [{'name': version.version, 'id': version.version}
for version in heat_api.heat.template_version_list(request)
if version.type == 'hot']
class APIThread(object):
thread_pool = pool.ThreadPool(processes=API_PARALLEL)
async_results = {}
def add_thread(self, apikey, func, args):
self.async_results[apikey] = self.thread_pool.apply_async(func, args)
def get_async_result(self, apikey):
if apikey not in self.async_results:
return [], None
try:
ret, err = self.async_results[apikey].get(
timeout=API_TIMEOUT)
except Exception as error:
ret, err = [], error.message
return ret, err
def _get_network_resources(options, all_networks):
try:
if all_networks:
options['networks'] = [
{'id': nw.id,
'name': nw.name if nw.name else '(%s)' % nw.id[: 6]}
for nw in all_networks if not getattr(nw, 'router:external')]
options['floating_networks'] = [
{'id': nw.id,
'name': nw.name if nw.name else '(%s)' % nw.id[: 6]}
for nw in all_networks if getattr(nw, 'router:external')]
else:
options['networks'] = []
options['floating_networks'] = []
except Exception:
options['networks'] = []
options['floating_networks'] = []
def _get_subnet_resources(options, all_subnets):
try:
if all_subnets and options.get('floating_networks'):
floating_network_ids = [nw.get('id')
for nw in options['floating_networks']]
options['subnets'] = [{'id': sb.id, 'name': sb.name}
for sb in all_subnets
if sb.network_id not in floating_network_ids]
options['floating_subnets'] = [
{'id': subnet.id, 'name': subnet.name}
for subnet in all_subnets
if subnet.network_id in floating_network_ids]
else:
options['subnets'] = []
options['floating_subnets'] = []
except Exception:
options['subnets'] = []
options['floating_subnets'] = []
def get_resource_options(request):
volumes = [{'id': vol.id,
'name': vol.name if vol.name else '(%s)' % vol.id}
for vol in dashboard_api.cinder.volume_list(request)]
volume_snapshots = [
{'id': volsnap.id,
'name': volsnap.name if volsnap.name else '(%s)' % volsnap.id[:6]}
for volsnap in dashboard_api.cinder.volume_snapshot_list(request)]
volume_types = [{
'id': voltype.id,
'name': voltype.name if voltype.name else '(%s)' % voltype.id[:6]}
for voltype in dashboard_api.cinder.volume_type_list(request)]
volume_backups = [
{'id': volbackup.id,
'name': volbackup.name
if volbackup.name else '(%s)' % volbackup.id[:6]}
for volbackup in dashboard_api.cinder.volume_backup_list(request)]
images = [
{'id': img.id,
'name': img.name if img.name else '(%s)' % img.id[:6]}
for img in dashboard_api.glance.image_list_detailed(request)[0]]
floatingips = [
{'id': fip.id, 'name': fip.floating_ip_address}
for fip in dashboard_api.neutron.tenant_floating_ip_list(
request, True)]
all_networks = dashboard_api.neutron.network_list(request)
networks = [{'id': nw.id,
'name': nw.name if nw.name else '(%s)' % nw.id[:6]}
for nw in all_networks if not nw['router:external']]
floating_networks = [{'id': nw.id,
'name': nw.name if nw.name else '(%s)' % nw.id[:6]}
for nw in all_networks if nw['router:external']]
floating_network_ids = [nw.get('id') for nw in floating_networks]
ports = [{'id': port.id,
'name': port.name if port.name else '(%s)' % port.id[:6]}
for port in dashboard_api.neutron.port_list(request)]
security_groups = [
{'id': secgroup.id,
'name': secgroup.name
if secgroup.name else '(%s)' % secgroup.id[:6]}
for secgroup in dashboard_api.neutron.security_group_list(request)]
all_subnets = dashboard_api.neutron.subnet_list(request)
subnets = [
{'id': subnet.id,
'name': subnet.name if subnet.name else '(%s)' % subnet.id[:6]}
for subnet in all_subnets]
floating_subnets = [{'id': subnet.id, 'name': subnet.name}
for subnet in all_subnets
if subnet.network_id in floating_network_ids]
routers = [
{'id': router.id,
'name': router.name if router.name else '(%s)' % router.id[:6]}
for router in dashboard_api.neutron.router_list(request)]
qos_policies = []
# qos_policies = [
# {'id': policy.id,
# 'name': policy.name
# if policy.name else '(%s)' % policy.id[:6]}
# for policy in dashboard_api.neutron.policy_list(request)]
availability_zones = [
{'id': az.zoneName, 'name': az.zoneName}
for az in dashboard_api.nova.availability_zone_list(request)]
flavors = [{'id': flavor.name, 'name': flavor.name}
for flavor in dashboard_api.nova.flavor_list(request)]
instances = [{'id': server.id,
'name': server.name
if server.name else '(%s)' % server.id[:6]}
for server in dashboard_api.nova.server_list(request)[0]]
keypairs = [{'name': keypair.name}
for keypair in dashboard_api.nova.keypair_list(request)]
template_versions = [
{'name': version.version, 'id': version.version}
for version in api.heat.template_version_list(request)
if version.type == 'hot']
opts = {
'auth': {
'tenant_id': request.user.tenant_id,
'admin': request.user.roles[0]['name'] == 'admin',
},
'volumes': volumes,
'volume_snapshots': volume_snapshots,
'volume_types': volume_types,
'volume_backups': volume_backups,
'images': images,
'floatingips': floatingips,
'floating_networks': floating_networks,
'floating_subnets': floating_subnets,
'networks': networks,
'ports': ports,
'security_groups': security_groups,
'subnets': subnets,
'routers': routers,
'qos_policies': qos_policies,
'availability_zones': availability_zones,
'flavors': flavors,
'instances': instances,
'keypairs': keypairs,
'template_versions': template_versions,
api_threads = APIThread()
api_mapping = {
'volumes': get_volume_ids,
'volume_snapshots': get_volume_snapshots,
'volume_types': get_volume_types,
'volume_backups': get_volume_backups,
'images': get_images,
'floatingips': get_floatingips,
'networks': get_networks,
'subnets': get_subnets,
'ports': get_ports,
'security_group': get_security_groups,
'routers': get_routers,
'qos_policies': get_qos_policies,
'availability_zones': get_availability_zones,
'flavors': get_flavors,
'instances': get_instances,
'keypairs': get_keypairs,
'template_versions': get_template_versions,
}
return json.dumps(opts)
options = {}
errors = {}
for resource, method in api_mapping.items():
api_threads.add_thread(resource, method, args=(request,))
for resource in api_mapping.keys():
ret, err = api_threads.get_async_result(resource)
options[resource] = ret
if err:
errors[resource.replace('_', ' ').capitalize()] = err
all_networks = options.pop('networks')
_get_network_resources(options, all_networks)
all_subnets = options.pop('subnets')
_get_subnet_resources(options, all_subnets)
role_names = []
for role in request.user.roles:
role_names.append(role.get('name'))
options.update({
'auth': {
'tenant_id': request.user.tenant_id,
'admin': 'admin' in role_names,
},
})
if len(errors.keys()) > 0:
options.update({'errors': errors})
return json.dumps(options)

View File

@ -16,8 +16,6 @@ from heat_dashboard.content.template_generator import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^get_resources$',
views.ApiView.as_view(), name="options"),
url(r'^get_resource_options$',
views.OptionView.as_view(), name="apis"),
]

View File

@ -17,7 +17,7 @@ from django.views import generic
from horizon.browsers.views import AngularIndexView
import api
from heat_dashboard.content.template_generator import api
class IndexView(AngularIndexView):
@ -25,12 +25,6 @@ class IndexView(AngularIndexView):
page_title = _("Template Generator")
class ApiView(generic.View):
def get(self, request):
return HttpResponse(api.get_resources(request),
content_type="application/json")
class OptionView(generic.View):
def get(self, request):
return HttpResponse(api.get_resource_options(request),

View File

@ -32,3 +32,9 @@ settings.POLICY_FILES.update({
# 'propagate': False,
# }
# })
# Template Generator retrieve options API TIMEOUT
API_TIMEOUT = 60
# Template Generator retrieve options API PARALLEL LEVEL
API_PARALLEL = 2

View File

@ -15,7 +15,17 @@
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
hotgenNotify.show_success('Retrieve openstack resources successfully.');
if (response.data.errors){
var msg = '';
angular.forEach(response.data.errors, function(value, key){
msg += key + ': '+ value + '. '
})
hotgenNotify.show_warning('Unable to retrieve resources '+msg+'.');
}
else{
hotgenNotify.show_success('Retrieve openstack resources successfully.');
}
return response.data;
}, function errorCallback(response) {
// called asynchronously if an error occurs

View File

@ -60,6 +60,26 @@
});
it('should return get_resource_options with errors', function(){
spyOn($location, 'absUrl').and.callFake(function (p) {
return 'http://some-url/';
});
requestHandler.respond(200, {
'auth': {
'tenant_id': 'tenant-id',
'admin': false,
},'errors': {'a': 'b'}}
);
$httpBackend.expectGET('http://some-url/get_resource_options');
var optionsPromise = hotgenAgent.get_resource_options();
optionsPromise.then(function(options){
expect(options.auth.tenant_id).toEqual('tenant-id');
expect(options.auth.admin).toEqual(false);
});
$httpBackend.flush();
});
it('should return error', function(){
spyOn($location, 'absUrl').and.callFake(function (p) {
return 'http://some-url';

View File

@ -14,6 +14,9 @@
$scope.nodes = hotgenStates.get_nodes();
$scope.selected = hotgenStates.get_selected();
$scope.toggle = function (item, list) {
if (typeof item == 'undefined' || !(list instanceof Array)){
return;
}
var idx = list.indexOf(item);
if (idx > -1) {
list.splice(idx, 1);
@ -24,7 +27,10 @@
};
$scope.exists = function (item, list) {
return list.indexOf(item) > -1;
if (typeof item != "undefined" && list instanceof Array){
return list.indexOf(item) > -1;
}
return false;
};
}
@ -46,4 +52,4 @@
}
});
})();
})();

View File

@ -0,0 +1,209 @@
# Copyright 2012 Nebula, Inc.
#
# 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 cinderclient.v2 import volume_backups as vol_backups
from cinderclient.v2 import volume_snapshots as vol_snaps
from cinderclient.v2 import volume_types
from cinderclient.v2 import volumes
from openstack_dashboard import api
from openstack_dashboard.test.test_data import utils
def data(TEST):
TEST.cinder_volumes = utils.TestDataContainer()
TEST.cinder_volume_backups = utils.TestDataContainer()
TEST.cinder_volume_types = utils.TestDataContainer()
TEST.cinder_volume_snapshots = utils.TestDataContainer()
# Volumes - Cinder v1
volume = volumes.Volume(
volumes.VolumeManager(None),
{'id': "11023e92-8008-4c8b-8059-7f2293ff3887",
'status': 'available',
'size': 40,
'display_name': 'Volume name',
'display_description': 'Volume description',
'created_at': '2014-01-27 10:30:00',
'volume_type': None,
'attachments': []})
nameless_volume = volumes.Volume(
volumes.VolumeManager(None),
{"id": "4b069dd0-6eaa-4272-8abc-5448a68f1cce",
"status": 'available',
"size": 10,
"display_name": '',
"display_description": '',
"device": "/dev/hda",
"created_at": '2010-11-21 18:34:25',
"volume_type": 'vol_type_1',
"attachments": []})
other_volume = volumes.Volume(
volumes.VolumeManager(None),
{'id': "21023e92-8008-1234-8059-7f2293ff3889",
'status': 'in-use',
'size': 10,
'display_name': u'my_volume',
'display_description': '',
'created_at': '2013-04-01 10:30:00',
'volume_type': None,
'attachments': [{"id": "1", "server_id": '1',
"device": "/dev/hda"}]})
volume_with_type = volumes.Volume(
volumes.VolumeManager(None),
{'id': "7dcb47fd-07d9-42c2-9647-be5eab799ebe",
'name': 'my_volume2',
'status': 'in-use',
'size': 10,
'display_name': u'my_volume2',
'display_description': '',
'created_at': '2013-04-01 10:30:00',
'volume_type': 'vol_type_2',
'attachments': [{"id": "2", "server_id": '2',
"device": "/dev/hdb"}]})
non_bootable_volume = volumes.Volume(
volumes.VolumeManager(None),
{'id': "21023e92-8008-1234-8059-7f2293ff3890",
'status': 'in-use',
'size': 10,
'display_name': u'my_volume',
'display_description': '',
'created_at': '2013-04-01 10:30:00',
'volume_type': None,
'bootable': False,
'attachments': [{"id": "1", "server_id": '1',
"device": "/dev/hda"}]})
volume.bootable = 'true'
nameless_volume.bootable = 'true'
other_volume.bootable = 'true'
TEST.cinder_volumes.add(api.cinder.Volume(volume))
TEST.cinder_volumes.add(api.cinder.Volume(nameless_volume))
TEST.cinder_volumes.add(api.cinder.Volume(other_volume))
TEST.cinder_volumes.add(api.cinder.Volume(volume_with_type))
TEST.cinder_volumes.add(api.cinder.Volume(non_bootable_volume))
vol_type1 = volume_types.VolumeType(volume_types.VolumeTypeManager(None),
{'id': u'1',
'name': u'vol_type_1',
'description': 'type 1 description',
'extra_specs': {'foo': 'bar',
'volume_backend_name':
'backend_1'}})
vol_type2 = volume_types.VolumeType(volume_types.VolumeTypeManager(None),
{'id': u'2',
'name': u'vol_type_2',
'description': 'type 2 description'})
vol_type3 = volume_types.VolumeType(volume_types.VolumeTypeManager(None),
{'id': u'3',
'name': u'vol_type_3',
'is_public': False,
'description': 'type 3 description'})
TEST.cinder_volume_types.add(vol_type1, vol_type2, vol_type3)
# Volumes - Cinder v2
volume_v2 = volumes.Volume(
volumes.VolumeManager(None),
{'id': "31023e92-8008-4c8b-8059-7f2293ff1234",
'name': 'v2_volume',
'description': "v2 Volume Description",
'status': 'available',
'size': 20,
'created_at': '2014-01-27 10:30:00',
'volume_type': None,
'os-vol-host-attr:host': 'host@backend-name#pool',
'bootable': 'true',
'attachments': []})
volume_v2.bootable = 'true'
TEST.cinder_volumes.add(api.cinder.Volume(volume_v2))
snapshot = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None),
{'id': '5f3d1c33-7d00-4511-99df-a2def31f3b5d',
'display_name': 'test snapshot',
'display_description': 'volume snapshot',
'size': 40,
'status': 'available',
'volume_id': '11023e92-8008-4c8b-8059-7f2293ff3887'})
snapshot2 = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None),
{'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0f',
'name': '',
'description': 'v2 volume snapshot description',
'size': 80,
'status': 'available',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
snapshot3 = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None),
{'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0e',
'name': '',
'description': 'v2 volume snapshot description 2',
'size': 80,
'status': 'available',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
snapshot4 = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None),
{'id': 'cd6be1eb-82ca-4587-8036-13c37c00c2b1',
'name': '',
'description': 'v2 volume snapshot with metadata description',
'size': 80,
'status': 'available',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234',
'metadata': {'snapshot_meta_key': 'snapshot_meta_value'}})
snapshot.bootable = 'true'
snapshot2.bootable = 'true'
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot))
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot2))
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot3))
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot4))
TEST.cinder_volume_snapshots.first()._volume = volume
volume_backup1 = vol_backups.VolumeBackup(
vol_backups.VolumeBackupManager(None),
{'id': 'a374cbb8-3f99-4c3f-a2ef-3edbec842e31',
'name': 'backup1',
'description': 'volume backup 1',
'size': 10,
'status': 'available',
'container_name': 'volumebackups',
'volume_id': '11023e92-8008-4c8b-8059-7f2293ff3887'})
volume_backup2 = vol_backups.VolumeBackup(
vol_backups.VolumeBackupManager(None),
{'id': 'c321cbb8-3f99-4c3f-a2ef-3edbec842e52',
'name': 'backup2',
'description': 'volume backup 2',
'size': 20,
'status': 'available',
'container_name': 'volumebackups',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
volume_backup3 = vol_backups.VolumeBackup(
vol_backups.VolumeBackupManager(None),
{'id': 'c321cbb8-3f99-4c3f-a2ef-3edbec842e53',
'name': 'backup3',
'description': 'volume backup 3',
'size': 20,
'status': 'available',
'container_name': 'volumebackups',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
TEST.cinder_volume_backups.add(volume_backup1)
TEST.cinder_volume_backups.add(volume_backup2)
TEST.cinder_volume_backups.add(volume_backup3)

View File

@ -0,0 +1,426 @@
# Copyright 2012 Nebula, Inc.
#
# 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 glanceclient.v1 import images
from openstack_dashboard import api
from heat_dashboard.test.test_data import utils
class Namespace(dict):
def __repr__(self):
return "<Namespace %s>" % self._info
def __init__(self, info):
super(Namespace, self).__init__()
self.__dict__.update(info)
self.update(info)
self._info = info
def as_json(self, indent=4):
return self.__dict__
class APIResourceV2(dict):
_base_props = [
'id', 'name', 'status', 'visibility', 'protected', 'checksum', 'owner',
'size', 'virtual_size', 'container_format', 'disk_format',
'created_at', 'updated_at', 'tags', 'direct_url', 'min_ram',
'min_disk', 'self', 'file', 'schema', 'locations']
def __getattr__(self, item):
if item == 'schema':
return {'properties': {k: '' for k in self._base_props}}
else:
return self.get(item)
def data(TEST):
TEST.images = utils.TestDataContainer()
TEST.images_api = utils.TestDataContainer()
TEST.snapshots = utils.TestDataContainer()
TEST.metadata_defs = utils.TestDataContainer()
TEST.imagesV2 = utils.TestDataContainer()
# Snapshots
snapshot_dict = {'name': u'snapshot',
'container_format': u'ami',
'id': 3,
'status': "active",
'owner': TEST.tenant.id,
'properties': {'image_type': u'snapshot'},
'is_public': False,
'protected': False}
snapshot_dict_no_owner = {'name': u'snapshot 2',
'container_format': u'ami',
'id': 4,
'status': "active",
'owner': None,
'properties': {'image_type': u'snapshot'},
'is_public': False,
'protected': False}
snapshot_dict_queued = {'name': u'snapshot 2',
'container_format': u'ami',
'id': 5,
'status': "queued",
'owner': TEST.tenant.id,
'properties': {'image_type': u'snapshot'},
'is_public': False,
'protected': False}
snapshot = images.Image(images.ImageManager(None), snapshot_dict)
TEST.snapshots.add(api.glance.Image(snapshot))
snapshot = images.Image(images.ImageManager(None), snapshot_dict_no_owner)
TEST.snapshots.add(api.glance.Image(snapshot))
snapshot = images.Image(images.ImageManager(None), snapshot_dict_queued)
TEST.snapshots.add(api.glance.Image(snapshot))
# Images
image_dict = {'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822',
'name': 'public_image',
'disk_format': u'qcow2',
'status': "active",
'size': 20 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'novaImage',
'properties': {'image_type': u'image'},
'is_public': True,
'protected': False,
'min_ram': 0,
'created_at': '2014-02-14T20:56:53'}
public_image = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': 'a001c047-22f8-47d0-80a1-8ec94a9524fe',
'name': 'private_image',
'status': "active",
'size': 10 * 1024 ** 2,
'virtual_size': 20 * 1024 ** 2,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'aki',
'is_public': False,
'protected': False,
'min_ram': 0,
'created_at': '2014-03-14T12:56:53'}
private_image = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': 'd6936c86-7fec-474a-85c5-5e467b371c3c',
'name': 'protected_images',
'status': "active",
'owner': TEST.tenant.id,
'size': 2 * 1024 ** 3,
'virtual_size': None,
'min_disk': 30,
'container_format': 'novaImage',
'properties': {'image_type': u'image'},
'is_public': True,
'protected': True,
'min_ram': 0,
'created_at': '2014-03-16T06:22:14'}
protected_image = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': '278905a6-4b52-4d1e-98f9-8c57bb25ba32',
'name': None,
'status': "active",
'size': 5 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'novaImage',
'properties': {'image_type': u'image'},
'is_public': True,
'protected': False,
'min_ram': 0}
public_image2 = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': '710a1acf-a3e3-41dd-a32d-5d6b6c86ea10',
'name': 'private_image 2',
'status': "active",
'size': 30 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'aki',
'is_public': False,
'protected': False,
'min_ram': 0}
private_image2 = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': '7cd892fd-5652-40f3-a450-547615680132',
'name': 'private_image 3',
'status': "active",
'size': 2 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'aki',
'is_public': False,
'protected': False,
'min_ram': 0}
private_image3 = images.Image(images.ImageManager(None), image_dict)
# A shared image. Not public and not local tenant.
image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849',
'name': 'shared_image 1',
'status': "active",
'size': 8 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': 'someothertenant',
'container_format': 'aki',
'is_public': False,
'protected': False,
'min_ram': 0}
shared_image1 = images.Image(images.ImageManager(None), image_dict)
# "Official" image. Public and tenant matches an entry
# in IMAGES_LIST_FILTER_TENANTS.
image_dict = {'id': 'f448704f-0ce5-4d34-8441-11b6581c6619',
'name': 'official_image 1',
'status': "active",
'size': 2 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': 'officialtenant',
'container_format': 'aki',
'is_public': True,
'protected': False,
'min_ram': 0}
official_image1 = images.Image(images.ImageManager(None), image_dict)
image_dict = {'id': 'a67e7d45-fe1e-4c5c-bf08-44b4a4964822',
'name': 'multi_prop_image',
'status': "active",
'size': 20 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': TEST.tenant.id,
'container_format': 'novaImage',
'properties': {'description': u'a multi prop image',
'foo': u'foo val',
'bar': u'bar val'},
'is_public': True,
'protected': False}
multi_prop_image = images.Image(images.ImageManager(None), image_dict)
# An image without name being returned based on current api
image_dict = {'id': 'c8756975-7a3b-4e43-b7f7-433576112849',
'status': "active",
'size': 8 * 1024 ** 3,
'virtual_size': None,
'min_disk': 0,
'owner': 'someothertenant',
'container_format': 'aki',
'is_public': False,
'protected': False}
no_name_image = images.Image(images.ImageManager(None), image_dict)
TEST.images_api.add(public_image, private_image, protected_image,
public_image2, private_image2, private_image3,
shared_image1, official_image1, multi_prop_image)
TEST.images.add(api.glance.Image(public_image),
api.glance.Image(private_image),
api.glance.Image(protected_image),
api.glance.Image(public_image2),
api.glance.Image(private_image2),
api.glance.Image(private_image3),
api.glance.Image(shared_image1),
api.glance.Image(official_image1),
api.glance.Image(multi_prop_image))
TEST.empty_name_image = api.glance.Image(no_name_image)
image_v2_dicts = [{
'checksum': 'eb9139e4942121f22bbc2afc0400b2a4',
'container_format': 'novaImage',
'created_at': '2014-02-14T20:56:53',
'direct_url': 'swift+config://ref1/glance/'
'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5',
'disk_format': u'qcow2',
'file': '/v2/images/'
'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5/file',
'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822',
'kernel_id': 'f6ebd5f0-b110-4406-8c1e-67b28d4e85e7',
'locations': [
{'metadata': {},
'url': 'swift+config://ref1/glance/'
'da8500d5-8b80-4b9c-8410-cc57fb8fb9d5'}],
'min_ram': 0,
'name': 'public_image',
'image_type': u'image',
'min_disk': 0,
'owner': TEST.tenant.id,
'protected': False,
'ramdisk_id': '868efefc-4f2d-4ed8-82b1-7e35576a7a47',
'size': 20 * 1024 ** 3,
'status': 'active',
'tags': ['active_image'],
'updated_at': '2015-08-31T19:37:45Z',
'virtual_size': None,
'visibility': 'public'
}, {
'checksum': None,
'container_format': 'novaImage',
'created_at': '2014-03-16T06:22:14',
'disk_format': None,
'image_type': u'image',
'file': '/v2/images/885d1cb0-9f5c-4677-9d03-175be7f9f984/file',
'id': 'd6936c86-7fec-474a-85c5-5e467b371c3c',
'locations': [],
'min_disk': 30,
'min_ram': 0,
'name': 'protected_images',
'owner': TEST.tenant.id,
'protected': True,
'size': 2 * 1024 ** 3,
'status': "active",
'tags': ['empty_image'],
'updated_at': '2015-09-01T22:37:32Z',
'virtual_size': None,
'visibility': 'public'
}, {
'checksum': 'e533283e6aac072533d1d091a7d2e413',
'container_format': 'novaImage',
'created_at': '2015-09-02T00:31:16Z',
'disk_format': 'qcow2',
'file': '/v2/images/10ca6b6b-48f4-43ac-8159-aa9e9353f5e4/file',
'id': 'a67e7d45-fe1e-4c5c-bf08-44b4a4964822',
'image_type': 'an image type',
'min_disk': 0,
'min_ram': 0,
'name': 'multi_prop_image',
'owner': TEST.tenant.id,
'protected': False,
'size': 20 * 1024 ** 3,
'status': 'active',
'tags': ['custom_property_image'],
'updated_at': '2015-09-02T00:31:17Z',
'virtual_size': None,
'visibility': 'public',
'description': u'a multi prop image',
'foo': u'foo val',
'bar': u'bar val'
}]
for fixture in image_v2_dicts:
apiresource = APIResourceV2(fixture)
TEST.imagesV2.add(api.glance.Image(apiresource))
metadef_dict = {
'namespace': 'namespace_1',
'display_name': 'Namespace 1',
'description': 'Mock desc 1',
'resource_type_associations': [
{
'created_at': '2014-08-21T08:39:43Z',
'prefix': 'mock',
'name': 'mock name'
}
],
'visibility': 'public',
'protected': True,
'created_at': '2014-08-21T08:39:43Z',
'properties': {
'cpu_mock:mock': {
'default': '1',
'type': 'integer',
'description': 'Number of mocks.',
'title': 'mocks'
}
}
}
metadef = Namespace(metadef_dict)
TEST.metadata_defs.add(metadef)
metadef_dict = {
'namespace': 'namespace_2',
'display_name': 'Namespace 2',
'description': 'Mock desc 2',
'resource_type_associations': [
{
'created_at': '2014-08-21T08:39:43Z',
'prefix': 'mock',
'name': 'mock name'
}
],
'visibility': 'private',
'protected': False,
'created_at': '2014-08-21T08:39:43Z',
'properties': {
'hdd_mock:mock': {
'default': '2',
'type': 'integer',
'description': 'Number of mocks.',
'title': 'mocks'
}
}
}
metadef = Namespace(metadef_dict)
TEST.metadata_defs.add(metadef)
metadef_dict = {
'namespace': 'namespace_3',
'display_name': 'Namespace 3',
'description': 'Mock desc 3',
'resource_type_associations': [
{
'created_at': '2014-08-21T08:39:43Z',
'prefix': 'mock',
'name': 'mock name'
}
],
'visibility': 'public',
'protected': False,
'created_at': '2014-08-21T08:39:43Z',
'properties': {
'gpu_mock:mock': {
'default': '2',
'type': 'integer',
'description': 'Number of mocks.',
'title': 'mocks'
}
}
}
metadef = Namespace(metadef_dict)
TEST.metadata_defs.add(metadef)
metadef_dict = {
'namespace': 'namespace_4',
'display_name': 'Namespace 4',
'description': 'Mock desc 4',
'resource_type_associations': [
{
'created_at': '2014-08-21T08:39:43Z',
'prefix': 'mock',
'name': 'OS::Cinder::Volume',
'properties_target': 'user'
}
],
'visibility': 'public',
'protected': True,
'created_at': '2014-08-21T08:39:43Z',
'properties': {
'ram_mock:mock': {
'default': '2',
'type': 'integer',
'description': 'Number of mocks.',
'title': 'mocks'
}
}
}
metadef = Namespace(metadef_dict)
TEST.metadata_defs.add(metadef)

View File

@ -22,6 +22,12 @@ from heat_dashboard.test.test_data import utils
def data(TEST):
# Data returned by openstack_dashboard.api.neutron wrapper.
TEST.networks = utils.TestDataContainer()
TEST.subnets = utils.TestDataContainer()
TEST.ports = utils.TestDataContainer()
TEST.routers = utils.TestDataContainer()
TEST.floating_ips = utils.TestDataContainer()
TEST.security_groups = utils.TestDataContainer()
TEST.qos_policies = utils.TestDataContainer()
# Data return by neutronclient.
TEST.api_networks = utils.TestDataContainer()
@ -75,3 +81,116 @@ def data(TEST):
subnetv6 = neutron.Subnet(subnetv6_dict)
network['subnets'] = [subnet, subnetv6]
TEST.networks.add(neutron.Network(network))
TEST.subnets.add(subnet)
TEST.subnets.add(subnetv6)
# Ports on 1st network.
port_dict = {
'admin_state_up': True,
'device_id': 'af75c8e5-a1cc-4567-8d04-44fcd6922890',
'device_owner': 'network:dhcp',
'fixed_ips': [{'ip_address': '10.0.0.3',
'subnet_id': subnet_dict['id']}],
'id': '063cf7f3-ded1-4297-bc4c-31eae876cc91',
'mac_address': 'fa:16:3e:9c:d5:7e',
'name': '',
'network_id': network_dict['id'],
'status': 'ACTIVE',
'tenant_id': network_dict['tenant_id'],
'binding:vnic_type': 'normal',
'binding:host_id': 'host',
'allowed_address_pairs': [
{'ip_address': '174.0.0.201',
'mac_address': 'fa:16:3e:7a:7b:18'}
],
'port_security_enabled': True,
'security_groups': [],
}
TEST.ports.add(neutron.Port(port_dict))
# External network.
network_dict = {'admin_state_up': True,
'id': '9b466b94-213a-4cda-badf-72c102a874da',
'name': 'ext_net',
'status': 'ACTIVE',
'subnets': ['d6bdc71c-7566-4d32-b3ff-36441ce746e8'],
'tenant_id': '3',
'router:external': True,
'shared': False}
subnet_dict = {'allocation_pools': [{'start': '172.24.4.226.',
'end': '172.24.4.238'}],
'dns_nameservers': [],
'host_routes': [],
'cidr': '172.24.4.0/28',
'enable_dhcp': False,
'gateway_ip': '172.24.4.225',
'id': 'd6bdc71c-7566-4d32-b3ff-36441ce746e8',
'ip_version': 4,
'name': 'ext_subnet',
'network_id': network_dict['id'],
'tenant_id': network_dict['tenant_id']}
ext_net = network_dict
network = copy.deepcopy(network_dict)
subnet = neutron.Subnet(subnet_dict)
network['subnets'] = [subnet]
TEST.networks.add(neutron.Network(network))
TEST.subnets.add(subnet)
assoc_port = port_dict
router_dict = {'id': '279989f7-54bb-41d9-ba42-0d61f12fda61',
'name': 'router1',
'status': 'ACTIVE',
'admin_state_up': True,
'distributed': True,
'external_gateway_info':
{'network_id': ext_net['id']},
'tenant_id': '1',
'availability_zone_hints': ['nova']}
TEST.routers.add(neutron.Router(router_dict))
# Associated (with compute port on 1st network).
fip_dict = {'tenant_id': '1',
'floating_ip_address': '172.16.88.228',
'floating_network_id': ext_net['id'],
'id': 'a97af8f2-3149-4b97-abbd-e49ad19510f7',
'fixed_ip_address': assoc_port['fixed_ips'][0]['ip_address'],
'port_id': assoc_port['id'],
'router_id': router_dict['id']}
fip_with_instance = copy.deepcopy(fip_dict)
fip_with_instance.update({'instance_id': '1',
'instance_type': 'compute'})
TEST.floating_ips.add(neutron.FloatingIp(fip_with_instance))
# Security group.
sec_group_1 = {'tenant_id': '1',
'description': 'default',
'id': 'faad7c80-3b62-4440-967c-13808c37131d',
'name': 'default'}
sec_group_2 = {'tenant_id': '1',
'description': 'NotDefault',
'id': '27a5c9a1-bdbb-48ac-833a-2e4b5f54b31d',
'name': 'other_group'}
sec_group_3 = {'tenant_id': '1',
'description': 'NotDefault',
'id': '443a4d7a-4bd2-4474-9a77-02b35c9f8c95',
'name': 'another_group'}
groups = [sec_group_1, sec_group_2, sec_group_3]
sg_name_dict = dict([(sg['id'], sg['name']) for sg in groups])
for sg in groups:
sg['security_group_rules'] = []
# OpenStack Dashboard internaly API.
TEST.security_groups.add(
neutron.SecurityGroup(copy.deepcopy(sg), sg_name_dict))
# qos policies
policy_dict = {'id': 'a21dcd22-7189-cccc-aa32-22adafaf16a7',
'name': 'policy 1',
'tenant_id': '1'}
TEST.qos_policies.add(neutron.QoSPolicy(policy_dict))
policy_dict1 = {'id': 'a21dcd22-7189-ssss-aa32-22adafaf16a7',
'name': 'policy 2',
'tenant_id': '1'}
TEST.qos_policies.add(neutron.QoSPolicy(policy_dict1))

View File

@ -0,0 +1,201 @@
# Copyright 2012 Nebula, Inc.
#
# 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 json
from novaclient.v2 import availability_zones
from novaclient.v2 import flavors
from novaclient.v2 import keypairs
from novaclient.v2 import servers
from heat_dashboard.test.test_data import utils
class FlavorExtraSpecs(dict):
def __repr__(self):
return "<FlavorExtraSpecs %s>" % self._info
def __init__(self, info):
super(FlavorExtraSpecs, self).__init__()
self.__dict__.update(info)
self.update(info)
self._info = info
SERVER_DATA = """
{
"server": {
"OS-EXT-SRV-ATTR:instance_name": "instance-00000005",
"OS-EXT-SRV-ATTR:host": "instance-host",
"OS-EXT-STS:task_state": null,
"addresses": {
"private": [
{
"version": 4,
"addr": "10.0.0.1"
}
]
},
"links": [
{
"href": "%(host)s/v1.1/%(tenant_id)s/servers/%(server_id)s",
"rel": "self"
},
{
"href": "%(host)s/%(tenant_id)s/servers/%(server_id)s",
"rel": "bookmark"
}
],
"image": {
"id": "%(image_id)s",
"links": [
{
"href": "%(host)s/%(tenant_id)s/images/%(image_id)s",
"rel": "bookmark"
}
]
},
"OS-EXT-STS:vm_state": "active",
"flavor": {
"id": "%(flavor_id)s",
"links": [
{
"href": "%(host)s/%(tenant_id)s/flavors/%(flavor_id)s",
"rel": "bookmark"
}
]
},
"id": "%(server_id)s",
"user_id": "%(user_id)s",
"OS-DCF:diskConfig": "MANUAL",
"accessIPv4": "",
"accessIPv6": "",
"progress": null,
"OS-EXT-STS:power_state": 1,
"config_drive": "",
"status": "%(status)s",
"updated": "2012-02-28T19:51:27Z",
"hostId": "c461ea283faa0ab5d777073c93b126c68139e4e45934d4fc37e403c2",
"key_name": "%(key_name)s",
"name": "%(name)s",
"created": "2012-02-28T19:51:17Z",
"tenant_id": "%(tenant_id)s",
"metadata": {"someMetaLabel": "someMetaData",
"some<b>html</b>label": "<!--",
"empty": ""}
}
}
"""
def data(TEST):
TEST.servers = utils.TestDataContainer()
TEST.flavors = utils.TestDataContainer()
TEST.keypairs = utils.TestDataContainer()
TEST.availability_zones = utils.TestDataContainer()
# Flavors
flavor_1 = flavors.Flavor(flavors.FlavorManager(None),
{'id': "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
'name': 'm1.tiny',
'vcpus': 1,
'disk': 0,
'ram': 512,
'swap': 0,
'rxtx_factor': 1,
'extra_specs': {},
'os-flavor-access:is_public': True,
'OS-FLV-EXT-DATA:ephemeral': 0})
flavor_2 = flavors.Flavor(flavors.FlavorManager(None),
{'id': "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
'name': 'm1.massive',
'vcpus': 1000,
'disk': 1024,
'ram': 10000,
'swap': 0,
'rxtx_factor': 1,
'extra_specs': {'Trusted': True, 'foo': 'bar'},
'os-flavor-access:is_public': True,
'OS-FLV-EXT-DATA:ephemeral': 2048})
flavor_3 = flavors.Flavor(flavors.FlavorManager(None),
{'id': "dddddddd-dddd-dddd-dddd-dddddddddddd",
'name': 'm1.secret',
'vcpus': 1000,
'disk': 1024,
'ram': 10000,
'swap': 0,
'rxtx_factor': 1,
'extra_specs': {},
'os-flavor-access:is_public': False,
'OS-FLV-EXT-DATA:ephemeral': 2048})
flavor_4 = flavors.Flavor(flavors.FlavorManager(None),
{'id': "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee",
'name': 'm1.metadata',
'vcpus': 1000,
'disk': 1024,
'ram': 10000,
'swap': 0,
'rxtx_factor': 1,
'extra_specs': FlavorExtraSpecs(
{'key': 'key_mock',
'value': 'value_mock'}),
'os-flavor-access:is_public': False,
'OS-FLV-EXT-DATA:ephemeral': 2048})
TEST.flavors.add(flavor_1, flavor_2, flavor_3, flavor_4)
# Key pairs
keypair = keypairs.Keypair(keypairs.KeypairManager(None),
dict(name='keyName'))
TEST.keypairs.add(keypair)
# Servers
vals = {"host": "http://nova.example.com:8774",
"name": "server_1",
"status": "ACTIVE",
"tenant_id": TEST.tenants.first().id,
"user_id": TEST.user.id,
"server_id": "1",
"flavor_id": flavor_1.id,
"image_id": TEST.images.first().id,
"key_name": keypair.name}
server_1 = servers.Server(servers.ServerManager(None),
json.loads(SERVER_DATA % vals)['server'])
vals.update({"name": "server_2",
"status": "BUILD",
"server_id": "2"})
server_2 = servers.Server(servers.ServerManager(None),
json.loads(SERVER_DATA % vals)['server'])
vals.update({"name": "server_4",
"status": "PAUSED",
"server_id": "4"})
server_4 = servers.Server(servers.ServerManager(None),
json.loads(SERVER_DATA % vals)['server'])
TEST.servers.add(server_1, server_2, server_4)
# Availability Zones
TEST.availability_zones.add(availability_zones.AvailabilityZone(
availability_zones.AvailabilityZoneManager(None),
{
'zoneName': 'nova',
'zoneState': {'available': True},
'hosts': {
"host001": {
"nova-network": {
"active": True,
"available": True,
},
},
},
},
))

View File

@ -14,18 +14,21 @@
def load_test_data(load_onto=None):
from heat_dashboard.test.test_data import cinder_data
from heat_dashboard.test.test_data import exceptions
from heat_dashboard.test.test_data import glance_data
from heat_dashboard.test.test_data import heat_data
from heat_dashboard.test.test_data import keystone_data
from heat_dashboard.test.test_data import neutron_data
from heat_dashboard.test.test_data import nova_data
# The order of these loaders matters, some depend on others.
loaders = (
exceptions.data,
keystone_data.data,
# glance_data.data,
# nova_data.data,
# cinder_data.data,
glance_data.data,
nova_data.data,
cinder_data.data,
neutron_data.data,
# swift_data.data,
heat_data.data,

View File

@ -0,0 +1,105 @@
# 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 json
from mox3.mox import IsA
from django.core.urlresolvers import reverse
from django import http
from openstack_dashboard import api as dashboard_api
from heat_dashboard import api
from heat_dashboard.test import helpers as test
class TemplateGeneratorTests(test.TestCase):
def test_index(self):
self.client.get(reverse('horizon:project:template_generator:index'))
self.assertTemplateUsed(
template_name='project/template_generator/index.html')
@test.create_stubs({
api.heat: ('template_version_list', ),
dashboard_api.neutron: (
'network_list', 'subnet_list', 'tenant_floating_ip_list',
'port_list', 'security_group_list', 'router_list', 'policy_list'),
dashboard_api.cinder: (
'volume_list', 'volume_snapshot_list',
'volume_type_list', 'volume_backup_list'),
dashboard_api.glance: ('image_list_detailed', ),
dashboard_api.nova: ('availability_zone_list', 'flavor_list',
'server_list', 'keypair_list')})
def test_option(self):
volumes = self.cinder_volumes.list()
volume_snapshots = self.cinder_volume_snapshots.list()
volume_types = self.cinder_volume_types.list()
volume_backups = self.cinder_volume_backups.list()
images = self.imagesV2.list()
networks = self.networks.list()
subnets = self.subnets.list()
floating_ips = self.floating_ips.list()
ports = self.ports.list()
security_groups = self.security_groups.list()
routers = self.routers.list()
qos_policies = self.qos_policies.list()
availability_zones = self.availability_zones.list()
flavors = self.flavors.list()
instances = self.servers.list()
keypairs = self.keypairs.list()
template_versions = self.template_versions.list()
dashboard_api.cinder.volume_list(
IsA(http.HttpRequest)).AndReturn(volumes)
dashboard_api.cinder.volume_snapshot_list(
IsA(http.HttpRequest)).AndReturn(volume_snapshots)
dashboard_api.cinder.volume_type_list(
IsA(http.HttpRequest)).AndReturn(volume_types)
dashboard_api.cinder.volume_backup_list(
IsA(http.HttpRequest)).AndReturn(volume_backups)
dashboard_api.glance.image_list_detailed(
IsA(http.HttpRequest)).AndReturn(images)
dashboard_api.neutron.network_list(
IsA(http.HttpRequest)).AndReturn(networks)
dashboard_api.neutron.subnet_list(
IsA(http.HttpRequest)).AndReturn(subnets)
dashboard_api.neutron.tenant_floating_ip_list(
IsA(http.HttpRequest), True).AndReturn(floating_ips)
dashboard_api.neutron.port_list(
IsA(http.HttpRequest)).AndReturn(ports)
dashboard_api.neutron.security_group_list(
IsA(http.HttpRequest)).AndReturn(security_groups)
dashboard_api.neutron.router_list(
IsA(http.HttpRequest)).AndReturn(routers)
dashboard_api.neutron.policy_list(
IsA(http.HttpRequest)).AndReturn(qos_policies)
dashboard_api.nova.availability_zone_list(
IsA(http.HttpRequest)).AndReturn(availability_zones)
dashboard_api.nova.flavor_list(
IsA(http.HttpRequest)).AndReturn(flavors)
dashboard_api.nova.server_list(
IsA(http.HttpRequest)).AndReturn(instances)
dashboard_api.nova.keypair_list(
IsA(http.HttpRequest)).AndReturn(keypairs)
api.heat.template_version_list(
IsA(http.HttpRequest)).AndReturn(template_versions)
self.mox.ReplayAll()
resp = self.client.get(reverse(
'horizon:project:template_generator:apis'))
data = resp.content
if isinstance(data, bytes):
data = data.decode('utf-8')
json_data = json.loads(data)
self.assertEqual(len(json_data.keys()), 20)