Coverage for nova/api/openstack/compute/views/images.py: 98%
50 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
1# Copyright 2010-2011 OpenStack Foundation
2# Copyright 2013 IBM Corp.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
17from oslo_utils import strutils
19from nova.api.openstack import common
20from nova.image import glance
21from nova import utils
24class ViewBuilder(common.ViewBuilder):
26 _collection_name = "images"
28 def basic(self, request, image):
29 """Return a dictionary with basic image attributes."""
30 return {
31 "image": {
32 "id": image.get("id"),
33 "name": image.get("name"),
34 "links": self._get_links(request,
35 image["id"],
36 self._collection_name),
37 },
38 }
40 def show(self, request, image):
41 """Return a dictionary with image details."""
42 image_dict = {
43 "id": image.get("id"),
44 "name": image.get("name"),
45 "minRam": int(image.get("min_ram") or 0),
46 "minDisk": int(image.get("min_disk") or 0),
47 "metadata": image.get("properties", {}),
48 "created": self._format_date(image.get("created_at")),
49 "updated": self._format_date(image.get("updated_at")),
50 "status": self._get_status(image),
51 "progress": self._get_progress(image),
52 "OS-EXT-IMG-SIZE:size": image.get("size"),
53 "links": self._get_links(request,
54 image["id"],
55 self._collection_name),
56 }
58 instance_uuid = image.get("properties", {}).get("instance_uuid")
60 if instance_uuid is not None:
61 server_ref = self._get_href_link(request, instance_uuid, 'servers')
62 image_dict["server"] = {
63 "id": instance_uuid,
64 "links": [{
65 "rel": "self",
66 "href": server_ref,
67 },
68 {
69 "rel": "bookmark",
70 "href": self._get_bookmark_link(request,
71 instance_uuid,
72 'servers'),
73 }],
74 }
76 auto_disk_config = image_dict['metadata'].get("auto_disk_config", None)
77 if auto_disk_config is not None:
78 value = strutils.bool_from_string(auto_disk_config)
79 image_dict["OS-DCF:diskConfig"] = (
80 'AUTO' if value else 'MANUAL')
82 return dict(image=image_dict)
84 def detail(self, request, images):
85 """Show a list of images with details."""
86 list_func = self.show
87 coll_name = self._collection_name + '/detail'
88 return self._list_view(list_func, request, images, coll_name)
90 def index(self, request, images):
91 """Show a list of images with basic attributes."""
92 list_func = self.basic
93 coll_name = self._collection_name
94 return self._list_view(list_func, request, images, coll_name)
96 def _list_view(self, list_func, request, images, coll_name):
97 """Provide a view for a list of images.
99 :param list_func: Function used to format the image data
100 :param request: API request
101 :param images: List of images in dictionary format
102 :param coll_name: Name of collection, used to generate the next link
103 for a pagination query
105 :returns: Image reply data in dictionary format
106 """
107 image_list = [list_func(request, image)["image"] for image in images]
108 images_links = self._get_collection_links(request, images, coll_name)
109 images_dict = dict(images=image_list)
111 if images_links:
112 images_dict["images_links"] = images_links
114 return images_dict
116 def _get_links(self, request, identifier, collection_name):
117 """Return a list of links for this image."""
118 return [{
119 "rel": "self",
120 "href": self._get_href_link(request, identifier, collection_name),
121 },
122 {
123 "rel": "bookmark",
124 "href": self._get_bookmark_link(request,
125 identifier,
126 collection_name),
127 },
128 {
129 "rel": "alternate",
130 "type": "application/vnd.openstack.image",
131 "href": self._get_alternate_link(request, identifier),
132 }]
134 def _get_alternate_link(self, request, identifier):
135 """Create an alternate link for a specific image id."""
136 glance_url = glance.generate_glance_url(
137 request.environ['nova.context'])
138 glance_url = self._update_glance_link_prefix(glance_url)
139 return '/'.join([glance_url,
140 self._collection_name,
141 str(identifier)])
143 @staticmethod
144 def _format_date(dt):
145 """Return standard format for a given datetime object."""
146 if dt is not None: 146 ↛ exitline 146 didn't return from function '_format_date' because the condition on line 146 was always true
147 return utils.isotime(dt)
149 @staticmethod
150 def _get_status(image):
151 """Update the status field to standardize format."""
152 return {
153 'active': 'ACTIVE',
154 'queued': 'SAVING',
155 'saving': 'SAVING',
156 'deleted': 'DELETED',
157 'pending_delete': 'DELETED',
158 'killed': 'ERROR',
159 }.get(image.get("status"), 'UNKNOWN')
161 @staticmethod
162 def _get_progress(image):
163 return {
164 "queued": 25,
165 "saving": 50,
166 "active": 100,
167 }.get(image.get("status"), 0)