~0x44/nova/extdoc

« back to all changes in this revision

Viewing changes to nova/image/glance.py

Update GlanceClient, GlanceImageService, and Glance Xen plugin to work with Glance keystone.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
import datetime
24
24
import json
25
25
import random
 
26
from urlparse import urlparse
26
27
 
27
28
from glance.common import exception as glance_exception
28
29
 
42
43
GlanceClient = utils.import_class('glance.client.Client')
43
44
 
44
45
 
 
46
def _parse_image_ref(image_href):
 
47
    """Parse an image href into composite parts.
 
48
 
 
49
    :param image_href: href of an image
 
50
    :returns: a tuple of the form (image_id, host, port)
 
51
    :raises ValueError
 
52
 
 
53
    """
 
54
    o = urlparse(image_href)
 
55
    port = o.port or 80
 
56
    host = o.netloc.split(':', 1)[0]
 
57
    image_id = int(o.path.split('/')[-1])
 
58
    return (image_id, host, port)
 
59
 
 
60
 
 
61
def _create_glance_client(context, host, port):
 
62
    if context.strategy == 'keystone':
 
63
        # NOTE(dprince): Glance client just needs auth_tok right? Should we
 
64
        # add username and tenant to the creds below?
 
65
        creds = {'strategy': 'keystone',
 
66
                 'username': context.user_id,
 
67
                 'tenant': context.project_id}
 
68
        glance_client = GlanceClient(host, port, auth_tok=context.auth_token,
 
69
                                     creds=creds)
 
70
    else:
 
71
        glance_client = GlanceClient(host, port)
 
72
    return glance_client
 
73
 
 
74
 
45
75
def pick_glance_api_server():
46
76
    """Return which Glance API server to use for the request
47
77
 
57
87
    return host, port
58
88
 
59
89
 
 
90
def get_glance_client(context, image_href):
 
91
    """Get the correct glance client and id for the given image_href.
 
92
 
 
93
    The image_href param can be an href of the form
 
94
    http://myglanceserver:9292/images/42, or just an int such as 42. If the
 
95
    image_href is an int, then flags are used to create the default
 
96
    glance client.
 
97
 
 
98
    :param image_href: image ref/id for an image
 
99
    :returns: a tuple of the form (glance_client, image_id)
 
100
 
 
101
    """
 
102
    image_href = image_href or 0
 
103
    if str(image_href).isdigit():
 
104
        glance_host, glance_port = pick_glance_api_server()
 
105
        glance_client = _create_glance_client(context, glance_host,
 
106
                                              glance_port)
 
107
        return (glance_client, int(image_href))
 
108
 
 
109
    try:
 
110
        (image_id, host, port) = _parse_image_ref(image_href)
 
111
    except ValueError:
 
112
        raise exception.InvalidImageRef(image_href=image_href)
 
113
    glance_client = _create_glance_client(context, glance_host, glance_port)
 
114
    return (glance_client, image_id)
 
115
 
 
116
 
60
117
class GlanceImageService(service.BaseImageService):
61
118
    """Provides storage and retrieval of disk image objects within Glance."""
62
119
 
71
128
    def __init__(self, client=None):
72
129
        self._client = client
73
130
 
74
 
    def _get_client(self):
 
131
    def _get_client(self, context):
75
132
        # NOTE(sirp): we want to load balance each request across glance
76
133
        # servers. Since GlanceImageService is a long-lived object, `client`
77
134
        # is made to choose a new server each time via this property.
78
135
        if self._client is not None:
79
136
            return self._client
80
137
        glance_host, glance_port = pick_glance_api_server()
81
 
        return GlanceClient(glance_host, glance_port)
82
 
 
83
 
    def _set_client(self, client):
84
 
        self._client = client
85
 
 
86
 
    client = property(_get_client, _set_client)
87
 
 
88
 
    def _set_client_context(self, context):
89
 
        """Sets the client's auth token."""
90
 
        self.client.set_auth_token(context.auth_token)
 
138
        return _create_glance_client(context, glance_host, glance_port)
91
139
 
92
140
    def index(self, context, **kwargs):
93
141
        """Calls out to Glance for a list of images available."""
128
176
 
129
177
    def _get_images(self, context, **kwargs):
130
178
        """Get image entitites from images service"""
131
 
        self._set_client_context(context)
132
179
 
133
180
        # ensure filters is a dict
134
181
        kwargs['filters'] = kwargs.get('filters') or {}
135
182
        # NOTE(vish): don't filter out private images
136
183
        kwargs['filters'].setdefault('is_public', 'none')
137
184
 
138
 
        return self._fetch_images(self.client.get_images_detailed, **kwargs)
 
185
        client = self._get_client(context)
 
186
        return self._fetch_images(client.get_images_detailed, **kwargs)
139
187
 
140
188
    def _fetch_images(self, fetch_func, **kwargs):
141
189
        """Paginate through results from glance server"""
168
216
 
169
217
    def show(self, context, image_id):
170
218
        """Returns a dict with image data for the given opaque image id."""
171
 
        self._set_client_context(context)
172
219
        try:
173
 
            image_meta = self.client.get_image_meta(image_id)
 
220
            image_meta = self._get_client(context).get_image_meta(image_id)
174
221
        except glance_exception.NotFound:
175
222
            raise exception.ImageNotFound(image_id=image_id)
176
223
 
192
239
 
193
240
    def get(self, context, image_id, data):
194
241
        """Calls out to Glance for metadata and data and writes data."""
195
 
        self._set_client_context(context)
196
242
        try:
197
 
            image_meta, image_chunks = self.client.get_image(image_id)
 
243
            client = self._get_client(context)
 
244
            image_meta, image_chunks = client.get_image(image_id)
198
245
        except glance_exception.NotFound:
199
246
            raise exception.ImageNotFound(image_id=image_id)
200
247
 
210
257
        :raises: AlreadyExists if the image already exist.
211
258
 
212
259
        """
213
 
        self._set_client_context(context)
214
260
        # Translate Base -> Service
215
261
        LOG.debug(_('Creating image in Glance. Metadata passed in %s'),
216
262
                  image_meta)
218
264
        LOG.debug(_('Metadata after formatting for Glance %s'),
219
265
                  sent_service_image_meta)
220
266
 
221
 
        recv_service_image_meta = self.client.add_image(
 
267
        recv_service_image_meta = self._get_client(context).add_image(
222
268
            sent_service_image_meta, data)
223
269
 
224
270
        # Translate Service -> Base
233
279
        :raises: ImageNotFound if the image does not exist.
234
280
 
235
281
        """
236
 
        self._set_client_context(context)
237
282
        # NOTE(vish): show is to check if image is available
238
283
        self.show(context, image_id)
239
284
        image_meta = _convert_to_string(image_meta)
240
285
        try:
241
 
            image_meta = self.client.update_image(image_id, image_meta, data)
 
286
            client = self._get_client(context)
 
287
            image_meta = client.update_image(image_id, image_meta, data)
242
288
        except glance_exception.NotFound:
243
289
            raise exception.ImageNotFound(image_id=image_id)
244
290
 
251
297
        :raises: ImageNotFound if the image does not exist.
252
298
 
253
299
        """
254
 
        self._set_client_context(context)
255
300
        # NOTE(vish): show is to check if image is available
256
301
        self.show(context, image_id)
257
302
        try:
258
 
            result = self.client.delete_image(image_id)
 
303
            result = self._get_client(context).delete_image(image_id)
259
304
        except glance_exception.NotFound:
260
305
            raise exception.ImageNotFound(image_id=image_id)
261
306
        return result