summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Lamar <brian.lamar@rackspace.com>2011-10-26 13:57:35 -0500
committerBrian Lamar <brian.lamar@rackspace.com>2011-11-16 17:33:40 -0500
commite7aa4022374fb35d2131a7c633212c5d6302db3d (patch)
treee23723c410275c12f74215e9dbf3f4a5fa69d4d6
parent217af7df5980ee7a258d2e8b24aea4444c083201 (diff)
Refactoring/cleanup of some view builders.
I have re-worked the "addresses", "flavors", "images", and "servers" view builders to share logic which was previously duplicated across many ViewBuilder classes. Also, I have re-worked the ViewBuilder class in general to persist longer. Overall we had good test coverage so not many tests had to be updated during the refactor. (Patch Set 2) Updated _set_request and _get_request to be a request property and a set_request method which can be overridden. (Patch Set 3) Fixed tests that I broke with the last update. (Patch Set 4) Changed "id in network.keys()" to "id in network" (Patch Set 5) Feedback changes from bcwaldon (Patch Set 6) Updated based on feedback from Waldon. (Patch Set 7) Feedback from s1rp (Rick Harris) Change-Id: I034404892018e99987f80789d7f7e406ff31658c
-rw-r--r--nova/api/openstack/common.py54
-rw-r--r--nova/api/openstack/contrib/createserverext.py36
-rw-r--r--nova/api/openstack/flavors.py49
-rw-r--r--nova/api/openstack/images.py21
-rw-r--r--nova/api/openstack/ips.py27
-rw-r--r--nova/api/openstack/servers.py60
-rw-r--r--nova/api/openstack/views/addresses.py58
-rw-r--r--nova/api/openstack/views/flavors.py93
-rw-r--r--nova/api/openstack/views/images.py271
-rw-r--r--nova/api/openstack/views/servers.py296
-rw-r--r--nova/api/openstack/wsgi.py10
-rw-r--r--nova/tests/api/openstack/test_images.py7
-rw-r--r--nova/tests/api/openstack/test_servers.py140
13 files changed, 516 insertions, 606 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index 3b82d358f..1a6800ac0 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -16,6 +16,7 @@
# under the License.
import functools
+import os
import re
import urlparse
@@ -428,3 +429,56 @@ def check_snapshots_enabled(f):
raise webob.exc.HTTPBadRequest(explanation=msg)
return f(*args, **kwargs)
return inner
+
+
+class ViewBuilder(object):
+ """Model API responses as dictionaries."""
+
+ _collection_name = None
+
+ def _get_links(self, request, identifier):
+ return [{
+ "rel": "self",
+ "href": self._get_href_link(request, identifier),
+ },
+ {
+ "rel": "bookmark",
+ "href": self._get_bookmark_link(request, identifier),
+ }]
+
+ def _get_next_link(self, request, identifier):
+ """Return href string with proper limit and marker params."""
+ params = request.params.copy()
+ params["marker"] = identifier
+ url = os.path.join(request.application_url,
+ request.environ["nova.context"].project_id,
+ self._collection_name)
+ return "%s?%s" % (url, dict_to_query_str(params))
+
+ def _get_href_link(self, request, identifier):
+ """Return an href string pointing to this object."""
+ return os.path.join(request.application_url,
+ request.environ["nova.context"].project_id,
+ self._collection_name,
+ str(identifier))
+
+ def _get_bookmark_link(self, request, identifier):
+ """Create a URL that refers to a specific resource."""
+ base_url = remove_version_from_href(request.application_url)
+ return os.path.join(base_url,
+ request.environ["nova.context"].project_id,
+ self._collection_name,
+ str(identifier))
+
+ def _get_collection_links(self, request, items):
+ """Retrieve 'next' link, if applicable."""
+ links = []
+ limit = int(request.params.get("limit", 0))
+ if limit and limit == len(items):
+ last_item = items[-1]
+ last_item_id = last_item.get("uuid", last_item["id"])
+ links.append({
+ "rel": "next",
+ "href": self._get_next_link(request, last_item_id),
+ })
+ return links
diff --git a/nova/api/openstack/contrib/createserverext.py b/nova/api/openstack/contrib/createserverext.py
index ab5037304..4e6556f5d 100644
--- a/nova/api/openstack/contrib/createserverext.py
+++ b/nova/api/openstack/contrib/createserverext.py
@@ -14,31 +14,30 @@
# License for the specific language governing permissions and limitations
# under the License
-from nova import utils
from nova.api.openstack import extensions
from nova.api.openstack import servers
+from nova.api.openstack import views
from nova.api.openstack import wsgi
-class CreateServerController(servers.Controller):
- def _build_view(self, req, instance, is_detail=False, is_create=False):
- server = super(CreateServerController, self).\
- _build_view(req,
- instance,
- is_detail=is_detail,
- is_create=is_create)
- if is_detail:
- self._build_security_groups(server['server'], instance)
+class ViewBuilder(views.servers.ViewBuilder):
+ """Adds security group output when viewing server details."""
+
+ def show(self, request, instance):
+ """Detailed view of a single instance."""
+ server = super(ViewBuilder, self).show(request, instance)
+ server["server"]["security_groups"] = self._get_groups(instance)
return server
- def _build_security_groups(self, response, inst):
- sg_names = []
- sec_groups = inst.get('security_groups')
- if sec_groups:
- sg_names = [sec_group['name'] for sec_group in sec_groups]
+ def _get_groups(self, instance):
+ """Get a list of security groups for this instance."""
+ groups = instance.get('security_groups')
+ if groups is not None:
+ return [{"name": group["name"]} for group in groups]
+
- response['security_groups'] = utils.convert_to_list_dict(sg_names,
- 'name')
+class Controller(servers.Controller):
+ _view_builder_class = ViewBuilder
class Createserverext(extensions.ExtensionDescriptor):
@@ -64,9 +63,10 @@ class Createserverext(extensions.ExtensionDescriptor):
serializer = wsgi.ResponseSerializer(body_serializers,
headers_serializer)
deserializer = wsgi.RequestDeserializer(body_deserializers)
+ controller = Controller()
res = extensions.ResourceExtension('os-create-server-ext',
- controller=CreateServerController(),
+ controller=controller,
deserializer=deserializer,
serializer=serializer)
resources.append(res)
diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py
index 7280ecbce..7680ef1ca 100644
--- a/nova/api/openstack/flavors.py
+++ b/nova/api/openstack/flavors.py
@@ -18,7 +18,7 @@
import webob
from lxml import etree
-from nova.api.openstack import views
+from nova.api.openstack.views import flavors as flavors_view
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import instance_types
@@ -26,20 +26,31 @@ from nova import db
from nova import exception
-class Controller(object):
+class Controller(wsgi.Controller):
"""Flavor controller for the OpenStack API."""
+ _view_builder_class = flavors_view.ViewBuilder
+
def index(self, req):
"""Return all flavors in brief."""
- items = self._get_flavors(req, is_detail=False)
- return dict(flavors=items)
+ flavors = self._get_flavors(req)
+ return self._view_builder.index(req, flavors)
def detail(self, req):
"""Return all flavors in detail."""
- items = self._get_flavors(req, is_detail=True)
- return dict(flavors=items)
+ flavors = self._get_flavors(req)
+ return self._view_builder.detail(req, flavors)
+
+ def show(self, req, id):
+ """Return data about the given flavor id."""
+ try:
+ flavor = instance_types.get_instance_type_by_flavor_id(id)
+ except exception.NotFound:
+ raise webob.exc.HTTPNotFound()
+
+ return self._view_builder.show(req, flavor)
- def _get_flavors(self, req, is_detail=True):
+ def _get_flavors(self, req):
"""Helper function that returns a list of flavor dicts."""
filters = {}
if 'minRam' in req.params:
@@ -54,29 +65,7 @@ class Controller(object):
except ValueError:
pass # ignore bogus values per spec
- ctxt = req.environ['nova.context']
- inst_types = instance_types.get_all_types(filters=filters)
- builder = self._get_view_builder(req)
- items = [builder.build(inst_type, is_detail=is_detail)
- for inst_type in inst_types.values()]
- return items
-
- def show(self, req, id):
- """Return data about the given flavor id."""
- try:
- ctxt = req.environ['nova.context']
- flavor = instance_types.get_instance_type_by_flavor_id(id)
- except exception.NotFound:
- raise webob.exc.HTTPNotFound()
-
- builder = self._get_view_builder(req)
- values = builder.build(flavor, is_detail=True)
- return dict(flavor=values)
-
- def _get_view_builder(self, req):
- base_url = req.application_url
- project_id = getattr(req.environ['nova.context'], 'project_id', '')
- return views.flavors.ViewBuilder(base_url, project_id)
+ return instance_types.get_all_types(filters=filters)
def make_flavor(elem, detailed=False):
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index b86b48ff5..f3ef63b49 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -26,9 +26,9 @@ from nova import log
from nova.api.openstack import common
from nova.api.openstack import image_metadata
from nova.api.openstack import servers
-from nova.api.openstack.views import images as images_view
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
+from nova.api.openstack.views import images as views_images
LOG = log.getLogger('nova.api.openstack.images')
@@ -45,16 +45,19 @@ SUPPORTED_FILTERS = {
}
-class Controller(object):
+class Controller(wsgi.Controller):
"""Base controller for retrieving/displaying images."""
- def __init__(self, image_service=None, compute_service=None):
+ _view_builder_class = views_images.ViewBuilder
+
+ def __init__(self, image_service=None, compute_service=None, **kwargs):
"""Initialize new `ImageController`.
:param compute_service: `nova.compute.api:API`
:param image_service: `nova.image.glance:GlancemageService`
"""
+ super(Controller, self).__init__(**kwargs)
self._compute_service = compute_service or compute.API()
self._image_service = image_service or \
nova.image.get_default_image_service()
@@ -88,7 +91,7 @@ class Controller(object):
explanation = _("Image not found.")
raise webob.exc.HTTPNotFound(explanation=explanation)
- return dict(image=self.get_builder(req).build(image, detail=True))
+ return self._view_builder.show(req, image)
def delete(self, req, id):
"""Delete an image, if allowed.
@@ -104,12 +107,6 @@ class Controller(object):
raise webob.exc.HTTPNotFound(explanation=explanation)
return webob.exc.HTTPNoContent()
- def get_builder(self, req):
- """Property to get the ViewBuilder class we need to use."""
- base_url = req.application_url
- project_id = getattr(req.environ['nova.context'], 'project_id', '')
- return images_view.ViewBuilder(base_url, project_id)
-
def index(self, req):
"""Return an index listing of images available to the request.
@@ -125,7 +122,7 @@ class Controller(object):
images = self._image_service.index(context, filters=filters,
**page_params)
- return self.get_builder(req).build_list(images, **params)
+ return self._view_builder.index(req, images)
def detail(self, req):
"""Return a detailed index listing of images available to the request.
@@ -142,7 +139,7 @@ class Controller(object):
images = self._image_service.detail(context, filters=filters,
**page_params)
- return self.get_builder(req).build_list(images, detail=True, **params)
+ return self._view_builder.detail(req, images)
def create(self, *args, **kwargs):
raise webob.exc.HTTPMethodNotAllowed()
diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py
index 1ab9a4fdc..2bef453a2 100644
--- a/nova/api/openstack/ips.py
+++ b/nova/api/openstack/ips.py
@@ -21,9 +21,9 @@ from webob import exc
import nova
from nova.api.openstack import common
-from nova.api.openstack.views import addresses as views_addresses
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
+from nova.api.openstack.views import addresses as view_addresses
from nova import log as logging
from nova import flags
@@ -32,15 +32,18 @@ LOG = logging.getLogger('nova.api.openstack.ips')
FLAGS = flags.FLAGS
-class Controller(object):
+class Controller(wsgi.Controller):
"""The servers addresses API controller for the Openstack API."""
- def __init__(self):
- self.compute_api = nova.compute.API()
+ _view_builder_class = view_addresses.ViewBuilder
+
+ def __init__(self, **kwargs):
+ super(Controller, self).__init__(**kwargs)
+ self._compute_api = nova.compute.API()
def _get_instance(self, context, server_id):
try:
- instance = self.compute_api.get(context, server_id)
+ instance = self._compute_api.get(context, server_id)
except nova.exception.NotFound:
msg = _("Instance does not exist")
raise exc.HTTPNotFound(explanation=msg)
@@ -53,25 +56,21 @@ class Controller(object):
raise exc.HTTPNotImplemented()
def index(self, req, server_id):
- context = req.environ['nova.context']
+ context = req.environ["nova.context"]
instance = self._get_instance(context, server_id)
networks = common.get_networks_for_instance(context, instance)
- return {'addresses': self._get_view_builder(req).build(networks)}
+ return self._view_builder.index(networks)
def show(self, req, server_id, id):
- context = req.environ['nova.context']
+ context = req.environ["nova.context"]
instance = self._get_instance(context, server_id)
networks = common.get_networks_for_instance(context, instance)
- network = self._get_view_builder(req).build_network(networks, id)
- if network is None:
+ if id not in networks:
msg = _("Instance is not a member of specified network")
raise exc.HTTPNotFound(explanation=msg)
- return network
-
- def _get_view_builder(self, req):
- return views_addresses.ViewBuilder()
+ return self._view_builder.show(networks[id], id)
def make_network(elem):
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 677635354..8b11b30f6 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -57,10 +57,13 @@ class ConvertedException(exc.WSGIHTTPException):
super(ConvertedException, self).__init__()
-class Controller(object):
+class Controller(wsgi.Controller):
""" The Server API base controller class for the OpenStack API """
- def __init__(self):
+ _view_builder_class = views_servers.ViewBuilder
+
+ def __init__(self, **kwargs):
+ super(Controller, self).__init__(**kwargs)
self.compute_api = compute.API()
self.network_api = network.API()
@@ -139,7 +142,10 @@ class Controller(object):
search_opts=search_opts)
limited_list = self._limit_items(instance_list, req)
- return self._build_list(req, limited_list, is_detail=is_detail)
+ if is_detail:
+ return self._view_builder.detail(req, limited_list)
+ else:
+ return self._view_builder.index(req, limited_list)
def _get_server(self, context, instance_uuid):
"""Utility function for looking up an instance by uuid"""
@@ -291,13 +297,12 @@ class Controller(object):
try:
instance = self.compute_api.routing_get(
req.environ['nova.context'], id)
- return self._build_view(req, instance, is_detail=True)
+ return self._view_builder.show(req, instance)
except exception.NotFound:
raise exc.HTTPNotFound()
def create(self, req, body):
""" Creates a new server for a given user """
-
if not body:
raise exc.HTTPUnprocessableEntity()
@@ -441,17 +446,13 @@ class Controller(object):
if ret_resv_id:
return {'reservation_id': resv_id}
- # Instances is a list
- instance = instances[0]
- if not instance.get('_is_precooked', False):
- instance['instance_type'] = inst_type
- instance['image_ref'] = image_href
+ server = self._view_builder.create(req, instances[0])
- server = self._build_view(req, instance, is_create=True)
- if '_is_precooked' in server['server']:
+ if '_is_precooked' in server['server'].keys():
del server['server']['_is_precooked']
else:
server['server']['adminPass'] = password
+
return server
def _delete(self, context, id):
@@ -497,13 +498,12 @@ class Controller(object):
raise exc.HTTPNotFound()
instance = self.compute_api.routing_get(ctxt, id)
- return self._build_view(req, instance, is_detail=True)
+ return self._view_builder.show(req, instance)
@exception.novaclient_converter
@scheduler_api.redirect_handler
def action(self, req, id, body):
"""Multi-purpose method used to take actions on a server"""
-
self.actions = {
'changePassword': self._action_change_password,
'reboot': self._action_reboot,
@@ -716,36 +716,6 @@ class Controller(object):
return common.get_id_from_href(flavor_ref)
- def _build_view(self, req, instance, is_detail=False, is_create=False):
- context = req.environ['nova.context']
- project_id = getattr(context, 'project_id', '')
- base_url = req.application_url
- flavor_builder = views_flavors.ViewBuilder(base_url, project_id)
- image_builder = views_images.ViewBuilder(base_url, project_id)
- addresses_builder = views_addresses.ViewBuilder()
- builder = views_servers.ViewBuilder(context, addresses_builder,
- flavor_builder, image_builder, base_url, project_id)
- return builder.build(instance,
- is_detail=is_detail,
- is_create=is_create)
-
- def _build_list(self, req, instances, is_detail=False):
- params = req.GET.copy()
- pagination_params = common.get_pagination_params(req)
- # Update params with int() values from pagination params
- for key, val in pagination_params.iteritems():
- params[key] = val
-
- context = req.environ['nova.context']
- project_id = getattr(context, 'project_id', '')
- base_url = req.application_url
- flavor_builder = views_flavors.ViewBuilder(base_url, project_id)
- image_builder = views_images.ViewBuilder(base_url, project_id)
- addresses_builder = views_addresses.ViewBuilder()
- builder = views_servers.ViewBuilder(context, addresses_builder,
- flavor_builder, image_builder, base_url, project_id)
- return builder.build_list(instances, is_detail=is_detail, **params)
-
def _action_change_password(self, input_dict, req, id):
context = req.environ['nova.context']
if (not 'changePassword' in input_dict
@@ -824,7 +794,7 @@ class Controller(object):
raise exc.HTTPNotFound(explanation=msg)
instance = self._get_server(context, instance_id)
- view = self._build_view(request, instance, is_detail=True)
+ view = self._view_builder.show(request, instance)
view['server']['adminPass'] = password
return view
diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py
index 2a5286646..1dbcaffe0 100644
--- a/nova/api/openstack/views/addresses.py
+++ b/nova/api/openstack/views/addresses.py
@@ -17,6 +17,7 @@
import itertools
+from nova.api.openstack import common
from nova import flags
from nova import log as logging
@@ -25,36 +26,27 @@ FLAGS = flags.FLAGS
LOG = logging.getLogger('nova.api.openstack.views.addresses')
-class ViewBuilder(object):
- """Models a server addresses response as a python dictionary."""
-
- def _extract_ips(self, network, key=None):
- if key:
- chain = network[key]
- else:
- chain = itertools.chain(network['ips'], network['floating_ips'])
- for ip in chain:
- if not FLAGS.use_ipv6 and ip['version'] == 6:
- continue
- yield ip
-
- def build(self, networks):
- result = {}
- for network in networks:
- if network not in result:
- result[network] = []
-
- result[network].extend(self._extract_ips(networks[network]))
- return result
-
- def build_network(self, networks, requested_network):
- for network in networks:
- if network == requested_network:
- return {network: list(self._extract_ips(networks[network]))}
- return None
-
- def _extract_network_label(self, network):
- try:
- return network['label']
- except (TypeError, KeyError) as exc:
- raise TypeError
+class ViewBuilder(common.ViewBuilder):
+ """Models server addresses as a dictionary."""
+
+ _collection_name = "addresses"
+
+ def basic(self, ip):
+ """Return a dictionary describing an IP address."""
+ return {
+ "version": ip["version"],
+ "addr": ip["addr"],
+ }
+
+ def show(self, network, label):
+ """Returns a dictionary describing a network."""
+ all_ips = itertools.chain(network["ips"], network["floating_ips"])
+ return {label: [self.basic(ip) for ip in all_ips]}
+
+ def index(self, networks):
+ """Return a dictionary describing a list of networks."""
+ addresses = {}
+ for label, network in networks.items():
+ network_dict = self.show(network, label)
+ addresses[label] = network_dict[label]
+ return dict(addresses=addresses)
diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py
index 9e180640b..f84ae5987 100644
--- a/nova/api/openstack/views/flavors.py
+++ b/nova/api/openstack/views/flavors.py
@@ -21,73 +21,46 @@ import os.path
from nova.api.openstack import common
-class ViewBuilder(object):
+class ViewBuilder(common.ViewBuilder):
- def __init__(self, base_url, project_id=""):
- """
- :param base_url: url of the root wsgi application
- """
- self.base_url = base_url
- self.project_id = project_id
+ _collection_name = "flavors"
- def build(self, flavor_obj, is_detail=False):
- """Generic method used to generate a flavor entity."""
- if is_detail:
- flavor = self._build_detail(flavor_obj)
- else:
- flavor = self._build_simple(flavor_obj)
-
- flavor["links"] = self._build_links(flavor)
-
- return flavor
-
- def _build_simple(self, flavor_obj):
- """Build a minimal representation of a flavor."""
+ def basic(self, request, flavor):
return {
- "id": flavor_obj["flavorid"],
- "name": flavor_obj["name"],
+ "flavor": {
+ "id": flavor["flavorid"],
+ "name": flavor["name"],
+ "links": self._get_links(request, flavor["flavorid"]),
+ },
}
- def _build_detail(self, flavor_obj):
- """Build a more complete representation of a flavor."""
- simple = self._build_simple(flavor_obj)
-
- detail = {
- "ram": flavor_obj["memory_mb"],
- "disk": flavor_obj["local_gb"],
+ def show(self, request, flavor):
+ return {
+ "flavor": {
+ "id": flavor["flavorid"],
+ "name": flavor["name"],
+ "ram": flavor["memory_mb"],
+ "disk": flavor["local_gb"],
+ "vcpus": flavor.get("vcpus") or "",
+ "swap": flavor.get("swap") or "",
+ "rxtx_quota": flavor.get("rxtx_quota") or "",
+ "rxtx_cap": flavor.get("rxtx_cap") or "",
+ "links": self._get_links(request, flavor["flavorid"]),
+ },
}
- for key in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"):
- detail[key] = flavor_obj.get(key, "")
-
- detail.update(simple)
-
- return detail
-
- def _build_links(self, flavor_obj):
- """Generate a container of links that refer to the provided flavor."""
- href = self.generate_href(flavor_obj["id"])
- bookmark = self.generate_bookmark(flavor_obj["id"])
-
- links = [
- {
- "rel": "self",
- "href": href,
- },
- {
- "rel": "bookmark",
- "href": bookmark,
- },
- ]
+ def index(self, request, flavors):
+ """Return the 'index' view of flavors."""
+ def _get_flavors(request, flavors):
+ for _, flavor in flavors.iteritems():
+ yield self.basic(request, flavor)["flavor"]
- return links
+ return dict(flavors=list(_get_flavors(request, flavors)))
- def generate_href(self, flavor_id):
- """Create an url that refers to a specific flavor id."""
- return os.path.join(self.base_url, self.project_id,
- "flavors", str(flavor_id))
+ def detail(self, request, flavors):
+ """Return the 'detail' view of flavors."""
+ def _get_flavors(request, flavors):
+ for _, flavor in flavors.iteritems():
+ yield self.show(request, flavor)["flavor"]
- def generate_bookmark(self, flavor_id):
- """Create an url that refers to a specific flavor id."""
- return os.path.join(common.remove_version_from_href(self.base_url),
- self.project_id, "flavors", str(flavor_id))
+ return dict(flavors=list(_get_flavors(request, flavors)))
diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py
index 9ef4c3ea0..c4cfe8031 100644
--- a/nova/api/openstack/views/images.py
+++ b/nova/api/openstack/views/images.py
@@ -21,180 +21,119 @@ from nova.api.openstack import common
from nova import utils
-class ViewBuilder(object):
- """Base class for generating responses to OpenStack API image requests."""
+class ViewBuilder(common.ViewBuilder):
- def __init__(self, base_url, project_id=""):
- """Initialize new `ViewBuilder`."""
- self.base_url = base_url
- self.project_id = project_id
+ _collection_name = "images"
- def _format_dates(self, image):
- """Update all date fields to ensure standardized formatting."""
- for attr in ['created_at', 'updated_at', 'deleted_at']:
- if image.get(attr) is not None:
- image[attr] = image[attr].strftime('%Y-%m-%dT%H:%M:%SZ')
+ def basic(self, request, image):
+ """Return a dictionary with basic image attributes."""
+ return {
+ "image": {
+ "id": image.get("id"),
+ "name": image.get("name"),
+ "links": self._get_links(request, image["id"]),
+ },
+ }
- def _format_status(self, image):
- """Update the status field to standardize format."""
+ def show(self, request, image):
+ """Return a dictionary with image details."""
+ image_dict = {
+ "id": image.get("id"),
+ "name": image.get("name"),
+ "minRam": int(image.get("min_ram") or 0),
+ "minDisk": int(image.get("min_disk") or 0),
+ "metadata": image.get("properties", {}),
+ "created": self._format_date(image.get("created_at")),
+ "updated": self._format_date(image.get("updated_at")),
+ "status": self._get_status(image),
+ "progress": self._get_progress(image),
+ "links": self._get_links(request, image["id"]),
+ }
- if 'status' not in image:
- return
+ server_ref = image.get("properties", {}).get("instance_ref")
+
+ if server_ref is not None:
+ image_dict["server"] = {
+ "id": common.get_id_from_href(server_ref),
+ "links": [{
+ "rel": "self",
+ "href": server_ref,
+ },
+ {
+ "rel": "bookmark",
+ "href": common.remove_version_from_href(server_ref),
+ }],
+ }
- status_mapping = {
+ return dict(image=image_dict)
+
+ def detail(self, request, images):
+ """Show a list of images with details."""
+ list_func = self.show
+ return self._list_view(list_func, request, images)
+
+ def index(self, request, images):
+ """Show a list of images with basic attributes."""
+ list_func = self.basic
+ return self._list_view(list_func, request, images)
+
+ def _list_view(self, list_func, request, images):
+ """Provide a view for a list of images."""
+ image_list = [list_func(request, image)["image"] for image in images]
+ images_links = self._get_collection_links(request, images)
+ images_dict = dict(images=image_list)
+
+ if images_links:
+ images_dict["images_links"] = images_links
+
+ return images_dict
+
+ def _get_links(self, request, identifier):
+ """Return a list of links for this image."""
+ return [{
+ "rel": "self",
+ "href": self._get_href_link(request, identifier),
+ },
+ {
+ "rel": "bookmark",
+ "href": self._get_bookmark_link(request, identifier),
+ },
+ {
+ "rel": "alternate",
+ "type": "application/vnd.openstack.image",
+ "href": self._get_alternate_link(request, identifier),
+ }]
+
+ def _get_alternate_link(self, request, identifier):
+ """Create an alternate link for a specific flavor id."""
+ glance_url = utils.generate_glance_url()
+ return os.path.join(glance_url,
+ request.environ["nova.context"].project_id,
+ self._collection_name,
+ str(identifier))
+
+ @staticmethod
+ def _format_date(date_string):
+ """Return standard format for given date."""
+ if date_string is not None:
+ return date_string.strftime('%Y-%m-%dT%H:%M:%SZ')
+
+ @staticmethod
+ def _get_status(image):
+ """Update the status field to standardize format."""
+ return {
'active': 'ACTIVE',
'queued': 'SAVING',
'saving': 'SAVING',
'deleted': 'DELETED',
'pending_delete': 'DELETED',
'killed': 'ERROR',
- }
-
- try:
- image['status'] = status_mapping[image['status']]
- except KeyError:
- image['status'] = 'UNKNOWN'
-
- def _get_progress_for_status(self, status):
- progress_map = {
- 'queued': 25,
- 'saving': 50,
- 'active': 100,
- }
- return progress_map.get(status, 0)
-
- def _build_server(self, image, image_obj):
- """Indicates that you must use a ViewBuilder subclass."""
- raise NotImplementedError()
-
- def generate_href(self, image_id):
- """Return an href string pointing to this object."""
- return os.path.join(self.base_url, "images", str(image_id))
-
- def build(self, image_obj, detail=False):
- """Return a standardized image structure for display by the API."""
- self._format_dates(image_obj)
-
- orig_status = image_obj.get('status', '').lower()
- self._format_status(image_obj)
-
- image = {
- "id": image_obj.get("id"),
- "name": image_obj.get("name"),
- }
-
- self._build_server(image, image_obj)
- self._build_image_id(image, image_obj)
-
- href = self.generate_href(image_obj["id"])
- bookmark = self.generate_bookmark(image_obj["id"])
- alternate = self.generate_alternate(image_obj["id"])
-
- image["links"] = [
- {
- "rel": "self",
- "href": href,
- },
- {
- "rel": "bookmark",
- "href": bookmark,
- },
- {
- "rel": "alternate",
- "type": "application/vnd.openstack.image",
- "href": alternate,
- },
-
- ]
-
- if detail:
- image.update({
- "created": image_obj.get("created_at"),
- "updated": image_obj.get("updated_at"),
- "status": image_obj.get("status"),
- })
- image["progress"] = self._get_progress_for_status(orig_status)
-
- image["metadata"] = image_obj.get("properties", {})
-
- min_ram = image_obj.get('min_ram') or 0
- try:
- min_ram = int(min_ram)
- except ValueError:
- min_ram = 0
- image['minRam'] = min_ram
-
- min_disk = image_obj.get('min_disk') or 0
- try:
- min_disk = int(min_disk)
- except ValueError:
- min_disk = 0
- image['minDisk'] = min_disk
-
- return image
-
- def _build_server(self, image, image_obj):
- try:
- serverRef = image_obj['properties']['instance_ref']
- image['server'] = {
- "id": common.get_id_from_href(serverRef),
- "links": [
- {
- "rel": "self",
- "href": serverRef,
- },
- {
- "rel": "bookmark",
- "href": common.remove_version_from_href(serverRef),
- },
- ]
- }
- except KeyError:
- return
-
- def _build_image_id(self, image, image_obj):
- image['id'] = "%s" % image_obj['id']
-
- def generate_href(self, image_id):
- """Return an href string pointing to this object."""
- return os.path.join(self.base_url, self.project_id,
- "images", str(image_id))
-
- def generate_next_link(self, image_id, params):
- """ Return an href string with proper limit and marker params"""
- params['marker'] = image_id
- return "%s?%s" % (
- os.path.join(self.base_url, self.project_id, "images"),
- common.dict_to_query_str(params))
-
- def build_list(self, image_objs, detail=False, **kwargs):
- """Return a standardized image list structure for display."""
- limit = kwargs.get('limit', None)
- images = []
- images_links = []
-
- for image_obj in image_objs:
- image = self.build(image_obj, detail=detail)
- images.append(image)
-
- if (len(images) and limit) and (limit == len(images)):
- next_link = self.generate_next_link(images[-1]["id"], kwargs)
- images_links = [dict(rel="next", href=next_link)]
-
- reval = dict(images=images)
- if len(images_links) > 0:
- reval['images_links'] = images_links
-
- return reval
-
- def generate_bookmark(self, image_id):
- """Create a URL that refers to a specific flavor id."""
- return os.path.join(common.remove_version_from_href(self.base_url),
- self.project_id, "images", str(image_id))
-
- def generate_alternate(self, image_id):
- """Create an alternate link for a specific flavor id."""
- glance_url = utils.generate_glance_url()
-
- return "%s/%s/images/%s" % (glance_url, self.project_id,
- str(image_id))
+ }.get(image.get("status"), 'UNKNOWN')
+
+ @staticmethod
+ def _get_progress(image):
+ return {
+ "queued": 25,
+ "saving": 50,
+ "active": 100,
+ }.get(image.get("status"), 0)
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index 4a0be46c1..e6f4bc2c4 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -20,6 +20,9 @@ import hashlib
import os
from nova.api.openstack import common
+from nova.api.openstack.views import addresses as views_addresses
+from nova.api.openstack.views import flavors as views_flavors
+from nova.api.openstack.views import images as views_images
from nova.compute import vm_states
from nova import exception
from nova import log as logging
@@ -29,168 +32,147 @@ from nova import utils
LOG = logging.getLogger('nova.api.openstack.views.servers')
-class ViewBuilder(object):
- """Model a server response as a python dictionary."""
-
- def __init__(self, context, addresses_builder, flavor_builder,
- image_builder, base_url, project_id=""):
- self.context = context
- self.addresses_builder = addresses_builder
- self.flavor_builder = flavor_builder
- self.image_builder = image_builder
- self.base_url = base_url
- self.project_id = project_id
-
- def build(self, inst, is_detail=False, is_create=False):
- """Return a dict that represenst a server."""
- if inst.get('_is_precooked', False):
- server = dict(server=inst)
- else:
- if is_detail:
- server = self._build_detail(inst)
- elif is_create:
- server = self._build_create(inst)
- else:
- server = self._build_simple(inst)
+class ViewBuilder(common.ViewBuilder):
+ """Model a server API response as a python dictionary."""
- self._build_links(server['server'], inst)
+ _collection_name = "servers"
- return server
+ _progress_statuses = (
+ "ACTIVE",
+ "BUILD",
+ "REBUILD",
+ "RESIZE",
+ "VERIFY_RESIZE",
+ )
- def _build_simple(self, inst):
- """Return a simple model of a server."""
- return dict(server=dict(id=inst['uuid'], name=inst['display_name']))
+ 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"]),
+ },
+ }
+
+ @_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"]),
+ },
+ }
+
+ @_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": utils.isotime(instance["created_at"]),
+ "updated": utils.isotime(instance["updated_at"]),
+ "addresses": self._get_addresses(request, instance),
+ "accessIPv4": instance.get("access_ip_v4") or "",
+ "accessIPv6": instance.get("access_ip_v6") or "",
+ "key_name": instance.get("key_name") or "",
+ "config_drive": instance.get("config_drive"),
+ "links": self._get_links(request, instance["uuid"]),
+ },
+ }
+
+ if server["server"]["status"] in self._progress_statuses:
+ server["server"]["progress"] = instance.get("progress", 0)
- def _build_create(self, inst):
- """Return data that should be returned from a server create."""
- server = dict(server=dict(id=inst['uuid']))
- self._build_links(server['server'], inst)
return server
- def _build_detail(self, inst):
- """Returns a detailed model of a server."""
- vm_state = inst.get('vm_state', vm_states.BUILDING)
- task_state = inst.get('task_state')
-
- inst_dict = {
- 'id': inst['uuid'],
- 'name': inst['display_name'],
- 'user_id': inst.get('user_id', ''),
- 'tenant_id': inst.get('project_id', ''),
- 'status': common.status_from_state(vm_state, task_state)}
-
- # Return the metadata as a dictionary
- metadata = {}
- for item in inst.get('metadata', []):
- metadata[item['key']] = str(item['value'])
- inst_dict['metadata'] = metadata
-
- inst_dict['hostId'] = ''
- if inst.get('host'):
- inst_dict['hostId'] = hashlib.sha224(inst['host']).hexdigest()
-
- self._build_image(inst_dict, inst)
- self._build_flavor(inst_dict, inst)
- networks = common.get_networks_for_instance(self.context, inst)
- self._build_addresses(inst_dict, networks)
-
- inst_dict['created'] = utils.isotime(inst['created_at'])
- inst_dict['updated'] = utils.isotime(inst['updated_at'])
-
- status = inst_dict.get('status')
- if status in ('ACTIVE', 'BUILD', 'REBUILD', 'RESIZE',
- 'VERIFY_RESIZE'):
- inst_dict['progress'] = inst['progress'] or 0
-
- inst_dict['accessIPv4'] = inst.get('access_ip_v4') or ""
- inst_dict['accessIPv6'] = inst.get('access_ip_v6') or ""
- inst_dict['key_name'] = inst.get('key_name', '')
- inst_dict['config_drive'] = inst.get('config_drive')
-
- return dict(server=inst_dict)
-
- def _build_addresses(self, response, networks):
- """Return the addresses sub-resource of a server."""
- response['addresses'] = self.addresses_builder.build(networks)
-
- def _build_image(self, response, inst):
- if inst.get("image_ref", None):
- image_href = inst['image_ref']
- image_id = str(common.get_id_from_href(image_href))
- _bookmark = self.image_builder.generate_bookmark(image_id)
- response['image'] = {
- "id": image_id,
- "links": [
- {
- "rel": "bookmark",
- "href": _bookmark,
- },
- ]
- }
-
- def _build_flavor(self, response, inst):
- if inst.get("instance_type", None):
- flavor_id = inst["instance_type"]['flavorid']
- flavor_ref = self.flavor_builder.generate_href(flavor_id)
- flavor_bookmark = self.flavor_builder.generate_bookmark(flavor_id)
- response["flavor"] = {
- "id": str(common.get_id_from_href(flavor_ref)),
- "links": [
- {
- "rel": "bookmark",
- "href": flavor_bookmark,
- },
- ]
- }
-
- def _build_links(self, response, inst):
- href = self.generate_href(inst["uuid"])
- bookmark = self.generate_bookmark(inst["uuid"])
-
- links = [
- {
- "rel": "self",
- "href": href,
- },
- {
+ def index(self, request, instances):
+ """Show a list of servers without many details."""
+ list_func = self.basic
+ return self._list_view(list_func, request, instances)
+
+ def detail(self, request, instances):
+ """Detailed view of a list of instance."""
+ list_func = self.show
+ return self._list_view(list_func, 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)
+ 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'], str(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")
+ if host:
+ return hashlib.sha224(host).hexdigest() # pylint: disable=E1101
+
+ 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"]
+ image_id = str(common.get_id_from_href(image_ref))
+ bookmark = self._image_builder._get_bookmark_link(request, image_id)
+ return {
+ "id": image_id,
+ "links": [{
"rel": "bookmark",
"href": bookmark,
- },
- ]
-
- response["links"] = links
-
- def build_list(self, server_objs, is_detail=False, **kwargs):
- limit = kwargs.get('limit', None)
- servers = []
- servers_links = []
-
- for server_obj in server_objs:
- servers.append(self.build(server_obj, is_detail)['server'])
-
- if (len(servers) and limit) and (limit == len(servers)):
- next_link = self.generate_next_link(servers[-1]['id'],
- kwargs, is_detail)
- servers_links = [dict(rel='next', href=next_link)]
-
- reval = dict(servers=servers)
- if len(servers_links) > 0:
- reval['servers_links'] = servers_links
- return reval
-
- def generate_next_link(self, server_id, params, is_detail=False):
- """ Return an href string with proper limit and marker params"""
- params['marker'] = server_id
- return "%s?%s" % (
- os.path.join(self.base_url, self.project_id, "servers"),
- common.dict_to_query_str(params))
-
- def generate_href(self, server_id):
- """Create an url that refers to a specific server id."""
- return os.path.join(self.base_url, self.project_id,
- "servers", str(server_id))
-
- def generate_bookmark(self, server_id):
- """Create an url that refers to a specific flavor id."""
- return os.path.join(common.remove_version_from_href(self.base_url),
- self.project_id, "servers", str(server_id))
+ }],
+ }
+
+ def _get_flavor(self, request, instance):
+ flavor_id = instance["instance_type"]["flavorid"]
+ flavor_ref = self._flavor_builder._get_href_link(request, flavor_id)
+ flavor_bookmark = self._flavor_builder._get_bookmark_link(request,
+ flavor_id)
+ return {
+ "id": str(common.get_id_from_href(flavor_ref)),
+ "links": [{
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ }],
+ }
diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py
index 1d1337626..8c6b30ca9 100644
--- a/nova/api/openstack/wsgi.py
+++ b/nova/api/openstack/wsgi.py
@@ -602,3 +602,13 @@ class Resource(wsgi.Application):
except TypeError as exc:
LOG.exception(exc)
return faults.Fault(webob.exc.HTTPBadRequest())
+
+
+class Controller(object):
+ """Default controller."""
+
+ _view_builder_class = None
+
+ def __init__(self, view_builder=None):
+ """Initialize controller with a view builder instance."""
+ self._view_builder = view_builder or self._view_builder_class()
diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py
index d42c66940..eb200046f 100644
--- a/nova/tests/api/openstack/test_images.py
+++ b/nova/tests/api/openstack/test_images.py
@@ -974,9 +974,10 @@ class ImagesControllerTest(test.TestCase):
self.mox.VerifyAll()
def test_generate_alternate_link(self):
- view = images_view.ViewBuilder(1)
- generated_url = view.generate_alternate(1)
- actual_url = "%s//images/1" % utils.generate_glance_url()
+ view = images_view.ViewBuilder()
+ request = fakes.HTTPRequest.blank('/v1.1/fake/images/1')
+ generated_url = view._get_alternate_link(request, 1)
+ actual_url = "%s/fake/images/1" % utils.generate_glance_url()
self.assertEqual(generated_url, actual_url)
def test_delete_image(self):
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 4588ca859..7eaaaa489 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -536,6 +536,30 @@ class ServersControllerTest(test.TestCase):
}
self.assertDictMatch(res_dict, expected)
+ def test_get_server_addresses_with_floating(self):
+ privates = ['192.168.0.3', '192.168.0.4']
+ publics = ['172.19.0.1', '1.2.3.4', '172.19.0.2']
+ new_return_server = return_server_with_attributes_by_uuid(
+ public_ips=publics, private_ips=privates,
+ public_ips_are_floating=True)
+ self.stubs.Set(nova.db, 'instance_get_by_uuid', new_return_server)
+
+ req = fakes.HTTPRequest.blank('/v1.1/fake/servers/%s/ips' % FAKE_UUID)
+ res_dict = self.ips_controller.index(req, FAKE_UUID)
+
+ expected = {
+ 'addresses': {
+ 'private': [
+ {'version': 4, 'addr': '192.168.0.3'},
+ {'version': 4, 'addr': '192.168.0.4'},
+ {'version': 4, 'addr': '172.19.0.1'},
+ {'version': 4, 'addr': '1.2.3.4'},
+ {'version': 4, 'addr': '172.19.0.2'},
+ ],
+ },
+ }
+ self.assertDictMatch(res_dict, expected)
+
def test_get_server_addresses_single_network(self):
self.flags(use_ipv6=True)
privates = ['192.168.0.3', '192.168.0.4']
@@ -589,6 +613,7 @@ class ServersControllerTest(test.TestCase):
if '_is_precooked' in s:
self.assertEqual(s.get('reservation_id'), 'child')
else:
+ print s
self.assertEqual(s.get('name'), 'server%d' % i)
i += 1
@@ -1369,7 +1394,8 @@ class ServersControllerCreateTest(test.TestCase):
req.headers["content-type"] = "application/json"
res = self.controller.create(req, body)
- self.assertEqual(['server'], res.keys())
+ self.assertEqual(FAKE_UUID, res["server"]["id"])
+ self.assertEqual(12, len(res["server"]["adminPass"]))
def test_create_multiple_instances_resv_id_return(self):
"""Test creating multiple instances with asking for
@@ -1518,24 +1544,6 @@ class ServersControllerCreateTest(test.TestCase):
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v1.1/images/%s' % image_uuid
flavor_ref = 'http://localhost/123/flavors/3'
- expected_flavor = {
- "id": "3",
- "links": [
- {
- "rel": "bookmark",
- "href": 'http://localhost/fake/flavors/3',
- },
- ],
- }
- expected_image = {
- "id": image_uuid,
- "links": [
- {
- "rel": "bookmark",
- "href": 'http://localhost/fake/images/%s' % image_uuid,
- },
- ],
- }
body = {
'server': {
'name': 'server_test',
@@ -1590,7 +1598,8 @@ class ServersControllerCreateTest(test.TestCase):
req.headers["content-type"] = "application/json"
res = self.controller.create(req, body)
- self.assertEqual(res.keys(), ['server'])
+ self.assertEqual(FAKE_UUID, res["server"]["id"])
+ self.assertEqual(12, len(res["server"]["adminPass"]))
def test_create_instance_invalid_flavor_href(self):
image_href = 'http://localhost/v1.1/images/2'
@@ -2295,26 +2304,12 @@ class ServersViewBuilderTest(test.TestCase):
include_fake_metadata=False)
self.uuid = self.instance['uuid']
- self.view_builder = self._get_view_builder()
-
- def _get_view_builder(self, project_id=""):
- base_url = "http://localhost/v1.1"
- views = nova.api.openstack.views
- address_builder = views.addresses.ViewBuilder()
- flavor_builder = views.flavors.ViewBuilder(base_url, project_id)
- image_builder = views.images.ViewBuilder(base_url, project_id)
-
- ctxt = context.RequestContext('fake_user', project_id)
- view_builder = nova.api.openstack.views.servers.ViewBuilder(
- ctxt,
- address_builder,
- flavor_builder,
- image_builder,
- base_url,
- project_id)
- return view_builder
+ self.view_builder = nova.api.openstack.views.servers.ViewBuilder()
+ self.request = fakes.HTTPRequest.blank("/v1.1")
def test_build_server(self):
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2322,17 +2317,17 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, False)
+ output = self.view_builder.basic(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_with_project_id(self):
@@ -2354,13 +2349,14 @@ class ServersViewBuilderTest(test.TestCase):
}
}
- view_builder = self._get_view_builder(project_id='fake')
- output = view_builder.build(self.instance, False)
+ output = self.view_builder.basic(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_detail(self):
- image_bookmark = "http://localhost/images/5"
- flavor_bookmark = "http://localhost/flavors/1"
+ image_bookmark = "http://localhost/fake/images/5"
+ flavor_bookmark = "http://localhost/fake/flavors/1"
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2407,25 +2403,27 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, True)
+ output = self.view_builder.show(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_detail_active_status(self):
#set the power state of the instance to running
self.instance['vm_state'] = vm_states.ACTIVE
self.instance['progress'] = 100
- image_bookmark = "http://localhost/images/5"
- flavor_bookmark = "http://localhost/flavors/1"
+ image_bookmark = "http://localhost/fake/images/5"
+ flavor_bookmark = "http://localhost/fake/flavors/1"
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2472,25 +2470,27 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, True)
+ output = self.view_builder.show(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_detail_with_accessipv4(self):
self.instance['access_ip_v4'] = '1.2.3.4'
- image_bookmark = "http://localhost/images/5"
- flavor_bookmark = "http://localhost/flavors/1"
+ image_bookmark = "http://localhost/fake/images/5"
+ flavor_bookmark = "http://localhost/fake/flavors/1"
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2537,25 +2537,27 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, True)
+ output = self.view_builder.show(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_detail_with_accessipv6(self):
self.instance['access_ip_v6'] = 'fead::1234'
- image_bookmark = "http://localhost/images/5"
- flavor_bookmark = "http://localhost/flavors/1"
+ image_bookmark = "http://localhost/fake/images/5"
+ flavor_bookmark = "http://localhost/fake/flavors/1"
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2602,17 +2604,17 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, True)
+ output = self.view_builder.show(self.request, self.instance)
self.assertDictMatch(output, expected_server)
def test_build_server_detail_with_metadata(self):
@@ -2622,8 +2624,10 @@ class ServersViewBuilderTest(test.TestCase):
metadata.append(InstanceMetadata(key="Number", value=1))
self.instance['metadata'] = metadata
- image_bookmark = "http://localhost/images/5"
- flavor_bookmark = "http://localhost/flavors/1"
+ image_bookmark = "http://localhost/fake/images/5"
+ flavor_bookmark = "http://localhost/fake/flavors/1"
+ self_link = "http://localhost/v1.1/fake/servers/%s" % self.uuid
+ bookmark_link = "http://localhost/fake/servers/%s" % self.uuid
expected_server = {
"server": {
"id": self.uuid,
@@ -2673,17 +2677,17 @@ class ServersViewBuilderTest(test.TestCase):
"links": [
{
"rel": "self",
- "href": "http://localhost/v1.1/servers/%s" % self.uuid,
+ "href": self_link,
},
{
"rel": "bookmark",
- "href": "http://localhost/servers/%s" % self.uuid,
+ "href": bookmark_link,
},
],
}
}
- output = self.view_builder.build(self.instance, True)
+ output = self.view_builder.show(self.request, self.instance)
self.assertDictMatch(output, expected_server)