1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13""" 14This module is a special module to define functions or other resources 15which need to be imported outside of openstack_dashboard.api.nova 16(like cinder.py) to avoid cyclic imports. 17""" 18 19from django.conf import settings 20from glanceclient import exc as glance_exceptions 21from novaclient import api_versions 22from novaclient import client as nova_client 23 24from horizon import exceptions as horizon_exceptions 25from horizon.utils import memoized 26 27from openstack_dashboard.api import base 28from openstack_dashboard.api import glance 29from openstack_dashboard.api import microversions 30from openstack_dashboard.contrib.developer.profiler import api as profiler 31 32 33# Supported compute versions 34VERSIONS = base.APIVersionManager("compute", preferred_version=2) 35VERSIONS.load_supported_version(1.1, {"client": nova_client, "version": 1.1}) 36VERSIONS.load_supported_version(2, {"client": nova_client, "version": 2}) 37 38INSECURE = settings.OPENSTACK_SSL_NO_VERIFY 39CACERT = settings.OPENSTACK_SSL_CACERT 40 41 42class Server(base.APIResourceWrapper): 43 """Simple wrapper around novaclient.server.Server. 44 45 Preserves the request info so image name can later be retrieved. 46 """ 47 _attrs = ['addresses', 'attrs', 'id', 'image', 'links', 'description', 48 'metadata', 'name', 'private_ip', 'public_ip', 'status', 'uuid', 49 'image_name', 'VirtualInterfaces', 'flavor', 'key_name', 'fault', 50 'tenant_id', 'user_id', 'created', 'locked', 51 'OS-EXT-STS:power_state', 'OS-EXT-STS:task_state', 52 'OS-EXT-SRV-ATTR:instance_name', 'OS-EXT-SRV-ATTR:host', 53 'OS-EXT-SRV-ATTR:hostname', 'OS-EXT-SRV-ATTR:kernel_id', 54 'OS-EXT-SRV-ATTR:ramdisk_id', 'OS-EXT-SRV-ATTR:root_device_name', 55 'OS-EXT-SRV-ATTR:root_device_name', 'OS-EXT-SRV-ATTR:user_data', 56 'OS-EXT-SRV-ATTR:reservation_id', 'OS-EXT-SRV-ATTR:launch_index', 57 'OS-EXT-AZ:availability_zone', 'OS-DCF:diskConfig'] 58 59 def __init__(self, apiresource, request): 60 super().__init__(apiresource) 61 self.request = request 62 63 # TODO(gabriel): deprecate making a call to Glance as a fallback. 64 @property 65 def image_name(self): 66 if not self.image: 67 return None 68 if hasattr(self.image, 'name'): 69 return self.image.name 70 if 'name' in self.image: 71 return self.image['name'] 72 try: 73 image = glance.image_get(self.request, self.image['id']) 74 self.image['name'] = image.name 75 return image.name 76 except (glance_exceptions.ClientException, 77 horizon_exceptions.ServiceCatalogException): 78 self.image['name'] = None 79 return None 80 81 @property 82 def availability_zone(self): 83 return getattr(self, 'OS-EXT-AZ:availability_zone', "") 84 85 @property 86 def has_extended_attrs(self): 87 return any(getattr(self, attr, None) for attr in [ 88 'OS-EXT-SRV-ATTR:instance_name', 'OS-EXT-SRV-ATTR:host', 89 'OS-EXT-SRV-ATTR:hostname', 'OS-EXT-SRV-ATTR:kernel_id', 90 'OS-EXT-SRV-ATTR:ramdisk_id', 'OS-EXT-SRV-ATTR:root_device_name', 91 'OS-EXT-SRV-ATTR:root_device_name', 'OS-EXT-SRV-ATTR:user_data', 92 'OS-EXT-SRV-ATTR:reservation_id', 'OS-EXT-SRV-ATTR:launch_index', 93 ]) 94 95 @property 96 def internal_name(self): 97 return getattr(self, 'OS-EXT-SRV-ATTR:instance_name', "") 98 99 @property 100 def host_server(self): 101 return getattr(self, 'OS-EXT-SRV-ATTR:host', "") 102 103 @property 104 def instance_name(self): 105 return getattr(self, 'OS-EXT-SRV-ATTR:instance_name', "") 106 107 @property 108 def reservation_id(self): 109 return getattr(self, 'OS-EXT-SRV-ATTR:reservation_id', "") 110 111 @property 112 def launch_index(self): 113 return getattr(self, 'OS-EXT-SRV-ATTR:launch_index', "") 114 115 @property 116 def hostname(self): 117 return getattr(self, 'OS-EXT-SRV-ATTR:hostname', "") 118 119 @property 120 def kernel_id(self): 121 return getattr(self, 'OS-EXT-SRV-ATTR:kernel_id', "") 122 123 @property 124 def ramdisk_id(self): 125 return getattr(self, 'OS-EXT-SRV-ATTR:ramdisk_id', "") 126 127 @property 128 def root_device_name(self): 129 return getattr(self, 'OS-EXT-SRV-ATTR:root_device_name', "") 130 131 @property 132 def user_data(self): 133 return getattr(self, 'OS-EXT-SRV-ATTR:user_data', "") 134 135 136@memoized.memoized 137def get_microversion(request, features): 138 client = novaclient(request) 139 min_ver, max_ver = api_versions._get_server_version_range(client) 140 return (microversions.get_microversion_for_features( 141 'nova', features, api_versions.APIVersion, min_ver, max_ver)) 142 143 144def get_auth_params_from_request(request): 145 """Extracts properties needed by novaclient call from the request object. 146 147 These will be used to memoize the calls to novaclient. 148 """ 149 return ( 150 request.user.username, 151 request.user.token.id, 152 request.user.tenant_id, 153 request.user.token.project.get('domain_id'), 154 base.url_for(request, 'compute'), 155 base.url_for(request, 'identity') 156 ) 157 158 159@memoized.memoized 160def cached_novaclient(request, version=None): 161 ( 162 username, 163 token_id, 164 project_id, 165 project_domain_id, 166 nova_url, 167 auth_url 168 ) = get_auth_params_from_request(request) 169 if version is None: 170 version = VERSIONS.get_active_version()['version'] 171 c = nova_client.Client(version, 172 username, 173 token_id, 174 project_id=project_id, 175 project_domain_id=project_domain_id, 176 auth_url=auth_url, 177 insecure=INSECURE, 178 cacert=CACERT, 179 http_log_debug=settings.DEBUG, 180 auth_token=token_id, 181 endpoint_override=nova_url) 182 return c 183 184 185def novaclient(request, version=None): 186 if isinstance(version, api_versions.APIVersion): 187 version = version.get_string() 188 return cached_novaclient(request, version) 189 190 191def get_novaclient_with_instance_desc(request): 192 microversion = get_microversion(request, "instance_description") 193 return novaclient(request, version=microversion) 194 195 196@profiler.trace 197def server_get(request, instance_id): 198 return Server(get_novaclient_with_instance_desc(request).servers.get( 199 instance_id), request) 200