d64f61f976
This removes a test that attempted to delete the data from the instance['instance_type'] structure and confirm that the flavor can still be fetched. Since this data is no longer consulted in that action (and will be removed altogether soon), this test is removed. This is one change in a series aimed at removing the use of instance-linked instance_type objects, in favor of the decoupled type data in system_metadata. See bug 1140119 for more details. Change-Id: I3ba56f9419aece5b9269a181264d09b117ecdb81
223 lines
8.0 KiB
Python
223 lines
8.0 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2010-2011 OpenStack Foundation
|
|
# Copyright 2011 Piston Cloud Computing, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 hashlib
|
|
|
|
from nova.api.openstack import common
|
|
from nova.api.openstack.compute.views import addresses as views_addresses
|
|
from nova.api.openstack.compute.views import flavors as views_flavors
|
|
from nova.api.openstack.compute.views import images as views_images
|
|
from nova.compute import instance_types
|
|
from nova.openstack.common import log as logging
|
|
from nova.openstack.common import timeutils
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class ViewBuilder(common.ViewBuilder):
|
|
"""Model a server API response as a python dictionary."""
|
|
|
|
_collection_name = "servers"
|
|
|
|
_progress_statuses = (
|
|
"ACTIVE",
|
|
"BUILD",
|
|
"REBUILD",
|
|
"RESIZE",
|
|
"VERIFY_RESIZE",
|
|
)
|
|
|
|
_fault_statuses = (
|
|
"ERROR",
|
|
)
|
|
|
|
def __init__(self):
|
|
"""Initialize view builder."""
|
|
super(ViewBuilder, self).__init__()
|
|
self._address_builder = views_addresses.ViewBuilder()
|
|
self._flavor_builder = views_flavors.ViewBuilder()
|
|
self._image_builder = views_images.ViewBuilder()
|
|
|
|
def _skip_precooked(func):
|
|
def wrapped(self, request, instance):
|
|
if instance.get("_is_precooked"):
|
|
return dict(server=instance)
|
|
else:
|
|
return func(self, request, instance)
|
|
return wrapped
|
|
|
|
def create(self, request, instance):
|
|
"""View that should be returned when an instance is created."""
|
|
return {
|
|
"server": {
|
|
"id": instance["uuid"],
|
|
"links": self._get_links(request,
|
|
instance["uuid"],
|
|
self._collection_name),
|
|
},
|
|
}
|
|
|
|
@_skip_precooked
|
|
def basic(self, request, instance):
|
|
"""Generic, non-detailed view of an instance."""
|
|
return {
|
|
"server": {
|
|
"id": instance["uuid"],
|
|
"name": instance["display_name"],
|
|
"links": self._get_links(request,
|
|
instance["uuid"],
|
|
self._collection_name),
|
|
},
|
|
}
|
|
|
|
@_skip_precooked
|
|
def show(self, request, instance):
|
|
"""Detailed view of a single instance."""
|
|
server = {
|
|
"server": {
|
|
"id": instance["uuid"],
|
|
"name": instance["display_name"],
|
|
"status": self._get_vm_state(instance),
|
|
"tenant_id": instance.get("project_id") or "",
|
|
"user_id": instance.get("user_id") or "",
|
|
"metadata": self._get_metadata(instance),
|
|
"hostId": self._get_host_id(instance) or "",
|
|
"image": self._get_image(request, instance),
|
|
"flavor": self._get_flavor(request, instance),
|
|
"created": timeutils.isotime(instance["created_at"]),
|
|
"updated": timeutils.isotime(instance["updated_at"]),
|
|
"addresses": self._get_addresses(request, instance),
|
|
"accessIPv4": instance.get("access_ip_v4") or "",
|
|
"accessIPv6": instance.get("access_ip_v6") or "",
|
|
"links": self._get_links(request,
|
|
instance["uuid"],
|
|
self._collection_name),
|
|
},
|
|
}
|
|
_inst_fault = self._get_fault(request, instance)
|
|
if server["server"]["status"] in self._fault_statuses and _inst_fault:
|
|
server['server']['fault'] = _inst_fault
|
|
|
|
if server["server"]["status"] in self._progress_statuses:
|
|
server["server"]["progress"] = instance.get("progress", 0)
|
|
|
|
return server
|
|
|
|
def index(self, request, instances):
|
|
"""Show a list of servers without many details."""
|
|
return self._list_view(self.basic, request, instances)
|
|
|
|
def detail(self, request, instances):
|
|
"""Detailed view of a list of instance."""
|
|
return self._list_view(self.show, request, instances)
|
|
|
|
def _list_view(self, func, request, servers):
|
|
"""Provide a view for a list of servers."""
|
|
server_list = [func(request, server)["server"] for server in servers]
|
|
servers_links = self._get_collection_links(request,
|
|
servers,
|
|
self._collection_name)
|
|
servers_dict = dict(servers=server_list)
|
|
|
|
if servers_links:
|
|
servers_dict["servers_links"] = servers_links
|
|
|
|
return servers_dict
|
|
|
|
@staticmethod
|
|
def _get_metadata(instance):
|
|
metadata = instance.get("metadata", [])
|
|
return dict((item['key'], item['value']) for item in metadata)
|
|
|
|
@staticmethod
|
|
def _get_vm_state(instance):
|
|
return common.status_from_state(instance.get("vm_state"),
|
|
instance.get("task_state"))
|
|
|
|
@staticmethod
|
|
def _get_host_id(instance):
|
|
host = instance.get("host")
|
|
project = str(instance.get("project_id"))
|
|
if host:
|
|
sha_hash = hashlib.sha224(project + host) # pylint: disable=E1101
|
|
return sha_hash.hexdigest()
|
|
|
|
def _get_addresses(self, request, instance):
|
|
context = request.environ["nova.context"]
|
|
networks = common.get_networks_for_instance(context, instance)
|
|
return self._address_builder.index(networks)["addresses"]
|
|
|
|
def _get_image(self, request, instance):
|
|
image_ref = instance["image_ref"]
|
|
if image_ref:
|
|
image_id = str(common.get_id_from_href(image_ref))
|
|
bookmark = self._image_builder._get_bookmark_link(request,
|
|
image_id,
|
|
"images")
|
|
return {
|
|
"id": image_id,
|
|
"links": [{
|
|
"rel": "bookmark",
|
|
"href": bookmark,
|
|
}],
|
|
}
|
|
else:
|
|
return ""
|
|
|
|
def _get_flavor(self, request, instance):
|
|
instance_type = instance_types.extract_instance_type(instance)
|
|
if not instance_type:
|
|
LOG.warn(_("Instance has had its instance_type removed "
|
|
"from the DB"), instance=instance)
|
|
return {}
|
|
flavor_id = instance_type["flavorid"]
|
|
flavor_bookmark = self._flavor_builder._get_bookmark_link(request,
|
|
flavor_id,
|
|
"flavors")
|
|
return {
|
|
"id": str(flavor_id),
|
|
"links": [{
|
|
"rel": "bookmark",
|
|
"href": flavor_bookmark,
|
|
}],
|
|
}
|
|
|
|
def _get_fault(self, request, instance):
|
|
fault = instance.get("fault", None)
|
|
|
|
if not fault:
|
|
return None
|
|
|
|
fault_dict = {
|
|
"code": fault["code"],
|
|
"created": timeutils.isotime(fault["created_at"]),
|
|
"message": fault["message"],
|
|
}
|
|
|
|
if fault.get('details', None):
|
|
is_admin = False
|
|
context = request.environ["nova.context"]
|
|
if context:
|
|
is_admin = getattr(context, 'is_admin', False)
|
|
|
|
if is_admin or fault['code'] != 500:
|
|
fault_dict['details'] = fault["details"]
|
|
|
|
return fault_dict
|