a20a275ef5
The previous code does not handle a case where admin-specific attributes do not exist. This leads to AttributeError in the project instance detail page as these attributes are not included in the response from nova API. Change-Id: I4c2942960259782d47c6777394dec6888959e26c Closes-Bug: #1905024
200 lines
6.9 KiB
Python
200 lines
6.9 KiB
Python
# 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 module is a special module to define functions or other resources
|
|
which need to be imported outside of openstack_dashboard.api.nova
|
|
(like cinder.py) to avoid cyclic imports.
|
|
"""
|
|
|
|
from django.conf import settings
|
|
from glanceclient import exc as glance_exceptions
|
|
from novaclient import api_versions
|
|
from novaclient import client as nova_client
|
|
|
|
from horizon import exceptions as horizon_exceptions
|
|
from horizon.utils import memoized
|
|
|
|
from openstack_dashboard.api import base
|
|
from openstack_dashboard.api import glance
|
|
from openstack_dashboard.api import microversions
|
|
from openstack_dashboard.contrib.developer.profiler import api as profiler
|
|
|
|
|
|
# Supported compute versions
|
|
VERSIONS = base.APIVersionManager("compute", preferred_version=2)
|
|
VERSIONS.load_supported_version(1.1, {"client": nova_client, "version": 1.1})
|
|
VERSIONS.load_supported_version(2, {"client": nova_client, "version": 2})
|
|
|
|
INSECURE = settings.OPENSTACK_SSL_NO_VERIFY
|
|
CACERT = settings.OPENSTACK_SSL_CACERT
|
|
|
|
|
|
class Server(base.APIResourceWrapper):
|
|
"""Simple wrapper around novaclient.server.Server.
|
|
|
|
Preserves the request info so image name can later be retrieved.
|
|
"""
|
|
_attrs = ['addresses', 'attrs', 'id', 'image', 'links', 'description',
|
|
'metadata', 'name', 'private_ip', 'public_ip', 'status', 'uuid',
|
|
'image_name', 'VirtualInterfaces', 'flavor', 'key_name', 'fault',
|
|
'tenant_id', 'user_id', 'created', 'locked',
|
|
'OS-EXT-STS:power_state', 'OS-EXT-STS:task_state',
|
|
'OS-EXT-SRV-ATTR:instance_name', 'OS-EXT-SRV-ATTR:host',
|
|
'OS-EXT-SRV-ATTR:hostname', 'OS-EXT-SRV-ATTR:kernel_id',
|
|
'OS-EXT-SRV-ATTR:ramdisk_id', 'OS-EXT-SRV-ATTR:root_device_name',
|
|
'OS-EXT-SRV-ATTR:root_device_name', 'OS-EXT-SRV-ATTR:user_data',
|
|
'OS-EXT-SRV-ATTR:reservation_id', 'OS-EXT-SRV-ATTR:launch_index',
|
|
'OS-EXT-AZ:availability_zone', 'OS-DCF:diskConfig']
|
|
|
|
def __init__(self, apiresource, request):
|
|
super().__init__(apiresource)
|
|
self.request = request
|
|
|
|
# TODO(gabriel): deprecate making a call to Glance as a fallback.
|
|
@property
|
|
def image_name(self):
|
|
if not self.image:
|
|
return None
|
|
if hasattr(self.image, 'name'):
|
|
return self.image.name
|
|
if 'name' in self.image:
|
|
return self.image['name']
|
|
try:
|
|
image = glance.image_get(self.request, self.image['id'])
|
|
self.image['name'] = image.name
|
|
return image.name
|
|
except (glance_exceptions.ClientException,
|
|
horizon_exceptions.ServiceCatalogException):
|
|
self.image['name'] = None
|
|
return None
|
|
|
|
@property
|
|
def availability_zone(self):
|
|
return getattr(self, 'OS-EXT-AZ:availability_zone', "")
|
|
|
|
@property
|
|
def has_extended_attrs(self):
|
|
return any(getattr(self, attr, None) for attr in [
|
|
'OS-EXT-SRV-ATTR:instance_name', 'OS-EXT-SRV-ATTR:host',
|
|
'OS-EXT-SRV-ATTR:hostname', 'OS-EXT-SRV-ATTR:kernel_id',
|
|
'OS-EXT-SRV-ATTR:ramdisk_id', 'OS-EXT-SRV-ATTR:root_device_name',
|
|
'OS-EXT-SRV-ATTR:root_device_name', 'OS-EXT-SRV-ATTR:user_data',
|
|
'OS-EXT-SRV-ATTR:reservation_id', 'OS-EXT-SRV-ATTR:launch_index',
|
|
])
|
|
|
|
@property
|
|
def internal_name(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:instance_name', "")
|
|
|
|
@property
|
|
def host_server(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:host', "")
|
|
|
|
@property
|
|
def instance_name(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:instance_name', "")
|
|
|
|
@property
|
|
def reservation_id(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:reservation_id', "")
|
|
|
|
@property
|
|
def launch_index(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:launch_index', "")
|
|
|
|
@property
|
|
def hostname(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:hostname', "")
|
|
|
|
@property
|
|
def kernel_id(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:kernel_id', "")
|
|
|
|
@property
|
|
def ramdisk_id(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:ramdisk_id', "")
|
|
|
|
@property
|
|
def root_device_name(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:root_device_name', "")
|
|
|
|
@property
|
|
def user_data(self):
|
|
return getattr(self, 'OS-EXT-SRV-ATTR:user_data', "")
|
|
|
|
|
|
@memoized.memoized
|
|
def get_microversion(request, features):
|
|
client = novaclient(request)
|
|
min_ver, max_ver = api_versions._get_server_version_range(client)
|
|
return (microversions.get_microversion_for_features(
|
|
'nova', features, api_versions.APIVersion, min_ver, max_ver))
|
|
|
|
|
|
def get_auth_params_from_request(request):
|
|
"""Extracts properties needed by novaclient call from the request object.
|
|
|
|
These will be used to memoize the calls to novaclient.
|
|
"""
|
|
return (
|
|
request.user.username,
|
|
request.user.token.id,
|
|
request.user.tenant_id,
|
|
request.user.token.project.get('domain_id'),
|
|
base.url_for(request, 'compute'),
|
|
base.url_for(request, 'identity')
|
|
)
|
|
|
|
|
|
@memoized.memoized
|
|
def cached_novaclient(request, version=None):
|
|
(
|
|
username,
|
|
token_id,
|
|
project_id,
|
|
project_domain_id,
|
|
nova_url,
|
|
auth_url
|
|
) = get_auth_params_from_request(request)
|
|
if version is None:
|
|
version = VERSIONS.get_active_version()['version']
|
|
c = nova_client.Client(version,
|
|
username,
|
|
token_id,
|
|
project_id=project_id,
|
|
project_domain_id=project_domain_id,
|
|
auth_url=auth_url,
|
|
insecure=INSECURE,
|
|
cacert=CACERT,
|
|
http_log_debug=settings.DEBUG,
|
|
auth_token=token_id,
|
|
endpoint_override=nova_url)
|
|
return c
|
|
|
|
|
|
def novaclient(request, version=None):
|
|
if isinstance(version, api_versions.APIVersion):
|
|
version = version.get_string()
|
|
return cached_novaclient(request, version)
|
|
|
|
|
|
def get_novaclient_with_instance_desc(request):
|
|
microversion = get_microversion(request, "instance_description")
|
|
return novaclient(request, version=microversion)
|
|
|
|
|
|
@profiler.trace
|
|
def server_get(request, instance_id):
|
|
return Server(get_novaclient_with_instance_desc(request).servers.get(
|
|
instance_id), request)
|