# 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 functools import wraps from multiprocessing import pool from django.conf import settings from openstack_dashboard import api as dashboard_api from heat_dashboard import api as heat_api try: API_TIMEOUT = settings.HEAT_TEMPLATE_GENERATOR_API_TIMEOUT except AttributeError: API_TIMEOUT = 60 try: API_PARALLEL = settings.HEAT_TEMPLATE_GENERATOR_API_PARALLEL except AttributeError: API_PARALLEL = 2 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 @handle_exception def get_networks(request): return dashboard_api.neutron.network_list(request) @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): 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_groups': 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, } 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)