Browse Source

Merge "Remove Images API v1 entry points"

tags/17.0.0.0b3^0
Zuul 10 months ago
parent
commit
ff77f59bd4

+ 0
- 2
glance/api/__init__.py View File

@@ -20,8 +20,6 @@ CONF = cfg.CONF
20 20
 
21 21
 
22 22
 def root_app_factory(loader, global_conf, **local_conf):
23
-    if not CONF.enable_v1_api and '/v1' in local_conf:
24
-        del local_conf['/v1']
25 23
     if not CONF.enable_v2_api and '/v2' in local_conf:
26 24
         del local_conf['/v2']
27 25
     return paste.urlmap.urlmap_factory(loader, global_conf, **local_conf)

+ 0
- 17
glance/api/middleware/cache.py View File

@@ -31,7 +31,6 @@ import webob
31 31
 
32 32
 from glance.api.common import size_checked_iter
33 33
 from glance.api import policy
34
-from glance.api.v1 import images
35 34
 from glance.common import exception
36 35
 from glance.common import utils
37 36
 from glance.common import wsgi
@@ -55,7 +54,6 @@ class CacheFilter(wsgi.Middleware):
55 54
 
56 55
     def __init__(self, app):
57 56
         self.cache = image_cache.ImageCache()
58
-        self.serializer = images.ImageSerializer()
59 57
         self.policy = policy.Enforcer()
60 58
         LOG.info(_LI("Initialized image cache middleware"))
61 59
         super(CacheFilter, self).__init__(app)
@@ -214,21 +212,6 @@ class CacheFilter(wsgi.Middleware):
214 212
         else:
215 213
             return (image_id, method, version)
216 214
 
217
-    def _process_v1_request(self, request, image_id, image_iterator,
218
-                            image_meta):
219
-        # Don't display location
220
-        if 'location' in image_meta:
221
-            del image_meta['location']
222
-        image_meta.pop('location_data', None)
223
-        self._verify_metadata(image_meta)
224
-
225
-        response = webob.Response(request=request)
226
-        raw_response = {
227
-            'image_iterator': image_iterator,
228
-            'image_meta': image_meta,
229
-        }
230
-        return self.serializer.show(response, raw_response)
231
-
232 215
     def _process_v2_request(self, request, image_id, image_iterator,
233 216
                             image_meta):
234 217
         # We do some contortions to get the image_metadata so

+ 0
- 4
glance/api/middleware/version_negotiation.py View File

@@ -72,10 +72,6 @@ class VersionNegotiationFilter(wsgi.Middleware):
72 72
 
73 73
     def _get_allowed_versions(self):
74 74
         allowed_versions = {}
75
-        if CONF.enable_v1_api:
76
-            allowed_versions['v1'] = 1
77
-            allowed_versions['v1.0'] = 1
78
-            allowed_versions['v1.1'] = 1
79 75
         if CONF.enable_v2_api:
80 76
             allowed_versions['v2'] = 2
81 77
             allowed_versions['v2.0'] = 2

+ 0
- 1351
glance/api/v1/images.py
File diff suppressed because it is too large
View File


+ 0
- 248
glance/api/v1/members.py View File

@@ -1,248 +0,0 @@
1
-# Copyright 2012 OpenStack Foundation.
2
-# Copyright 2013 NTT 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.
16
-
17
-from oslo_config import cfg
18
-from oslo_log import log as logging
19
-from oslo_utils import encodeutils
20
-import webob.exc
21
-
22
-from glance.api import policy
23
-from glance.api.v1 import controller
24
-from glance.common import exception
25
-from glance.common import utils
26
-from glance.common import wsgi
27
-from glance.i18n import _
28
-import glance.registry.client.v1.api as registry
29
-
30
-LOG = logging.getLogger(__name__)
31
-CONF = cfg.CONF
32
-CONF.import_opt('image_member_quota', 'glance.common.config')
33
-
34
-
35
-class Controller(controller.BaseController):
36
-
37
-    def __init__(self):
38
-        self.policy = policy.Enforcer()
39
-
40
-    def _check_can_access_image_members(self, context):
41
-        if context.owner is None and not context.is_admin:
42
-            raise webob.exc.HTTPUnauthorized(_("No authenticated user"))
43
-
44
-    def _enforce(self, req, action):
45
-        """Authorize an action against our policies"""
46
-        try:
47
-            self.policy.enforce(req.context, action, {})
48
-        except exception.Forbidden:
49
-            LOG.debug("User not permitted to perform '%s' action", action)
50
-            raise webob.exc.HTTPForbidden()
51
-
52
-    def _raise_404_if_image_deleted(self, req, image_id):
53
-        image = self.get_image_meta_or_404(req, image_id)
54
-        if image['status'] == 'deleted':
55
-            msg = _("Image with identifier %s has been deleted.") % image_id
56
-            raise webob.exc.HTTPNotFound(msg)
57
-
58
-    def index(self, req, image_id):
59
-        """
60
-        Return a list of dictionaries indicating the members of the
61
-        image, i.e., those tenants the image is shared with.
62
-
63
-        :param req: the Request object coming from the wsgi layer
64
-        :param image_id: The opaque image identifier
65
-        :returns: The response body is a mapping of the following form
66
-
67
-        ::
68
-
69
-            {'members': [
70
-                {'member_id': <MEMBER>,
71
-                 'can_share': <SHARE_PERMISSION>, ...}, ...
72
-            ]}
73
-
74
-        """
75
-        self._enforce(req, 'get_members')
76
-        self._raise_404_if_image_deleted(req, image_id)
77
-
78
-        try:
79
-            members = registry.get_image_members(req.context, image_id)
80
-        except exception.NotFound:
81
-            msg = _("Image with identifier %s not found") % image_id
82
-            LOG.warn(msg)
83
-            raise webob.exc.HTTPNotFound(msg)
84
-        except exception.Forbidden:
85
-            msg = _("Unauthorized image access")
86
-            LOG.warn(msg)
87
-            raise webob.exc.HTTPForbidden(msg)
88
-        return dict(members=members)
89
-
90
-    @utils.mutating
91
-    def delete(self, req, image_id, id):
92
-        """
93
-        Removes a membership from the image.
94
-        """
95
-        self._check_can_access_image_members(req.context)
96
-        self._enforce(req, 'delete_member')
97
-        self._raise_404_if_image_deleted(req, image_id)
98
-
99
-        try:
100
-            registry.delete_member(req.context, image_id, id)
101
-            self._update_store_acls(req, image_id)
102
-        except exception.NotFound as e:
103
-            LOG.debug(encodeutils.exception_to_unicode(e))
104
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
105
-        except exception.Forbidden as e:
106
-            LOG.debug("User not permitted to remove membership from image "
107
-                      "'%s'", image_id)
108
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
109
-
110
-        return webob.exc.HTTPNoContent()
111
-
112
-    def default(self, req, image_id, id, body=None):
113
-        """This will cover the missing 'show' and 'create' actions"""
114
-        raise webob.exc.HTTPMethodNotAllowed()
115
-
116
-    def _enforce_image_member_quota(self, req, attempted):
117
-        if CONF.image_member_quota < 0:
118
-            # If value is negative, allow unlimited number of members
119
-            return
120
-
121
-        maximum = CONF.image_member_quota
122
-        if attempted > maximum:
123
-            msg = _("The limit has been exceeded on the number of allowed "
124
-                    "image members for this image. Attempted: %(attempted)s, "
125
-                    "Maximum: %(maximum)s") % {'attempted': attempted,
126
-                                               'maximum': maximum}
127
-            raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg,
128
-                                                      request=req)
129
-
130
-    @utils.mutating
131
-    def update(self, req, image_id, id, body=None):
132
-        """
133
-        Adds a membership to the image, or updates an existing one.
134
-        If a body is present, it is a dict with the following format
135
-
136
-        ::
137
-
138
-            {'member': {
139
-                'can_share': [True|False]
140
-            }}
141
-
142
-        If `can_share` is provided, the member's ability to share is
143
-        set accordingly.  If it is not provided, existing memberships
144
-        remain unchanged and new memberships default to False.
145
-        """
146
-        self._check_can_access_image_members(req.context)
147
-        self._enforce(req, 'modify_member')
148
-        self._raise_404_if_image_deleted(req, image_id)
149
-
150
-        new_number_of_members = len(registry.get_image_members(req.context,
151
-                                                               image_id)) + 1
152
-        self._enforce_image_member_quota(req, new_number_of_members)
153
-
154
-        # Figure out can_share
155
-        can_share = None
156
-        if body and 'member' in body and 'can_share' in body['member']:
157
-            can_share = bool(body['member']['can_share'])
158
-        try:
159
-            registry.add_member(req.context, image_id, id, can_share)
160
-            self._update_store_acls(req, image_id)
161
-        except exception.Invalid as e:
162
-            LOG.debug(encodeutils.exception_to_unicode(e))
163
-            raise webob.exc.HTTPBadRequest(explanation=e.msg)
164
-        except exception.NotFound as e:
165
-            LOG.debug(encodeutils.exception_to_unicode(e))
166
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
167
-        except exception.Forbidden as e:
168
-            LOG.debug(encodeutils.exception_to_unicode(e))
169
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
170
-
171
-        return webob.exc.HTTPNoContent()
172
-
173
-    @utils.mutating
174
-    def update_all(self, req, image_id, body):
175
-        """
176
-        Replaces the members of the image with those specified in the
177
-        body.  The body is a dict with the following format
178
-
179
-        ::
180
-
181
-            {'memberships': [
182
-                {'member_id': <MEMBER_ID>,
183
-                 ['can_share': [True|False]]}, ...
184
-            ]}
185
-
186
-        """
187
-        self._check_can_access_image_members(req.context)
188
-        self._enforce(req, 'modify_member')
189
-        self._raise_404_if_image_deleted(req, image_id)
190
-
191
-        memberships = body.get('memberships')
192
-        if memberships:
193
-            new_number_of_members = len(body['memberships'])
194
-            self._enforce_image_member_quota(req, new_number_of_members)
195
-
196
-        try:
197
-            registry.replace_members(req.context, image_id, body)
198
-            self._update_store_acls(req, image_id)
199
-        except exception.Invalid as e:
200
-            LOG.debug(encodeutils.exception_to_unicode(e))
201
-            raise webob.exc.HTTPBadRequest(explanation=e.msg)
202
-        except exception.NotFound as e:
203
-            LOG.debug(encodeutils.exception_to_unicode(e))
204
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
205
-        except exception.Forbidden as e:
206
-            LOG.debug(encodeutils.exception_to_unicode(e))
207
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
208
-
209
-        return webob.exc.HTTPNoContent()
210
-
211
-    def index_shared_images(self, req, id):
212
-        """
213
-        Retrieves list of image memberships for the given member.
214
-
215
-        :param req: the Request object coming from the wsgi layer
216
-        :param id: the opaque member identifier
217
-        :returns: The response body is a mapping of the following form
218
-
219
-        ::
220
-
221
-            {'shared_images': [
222
-                {'image_id': <IMAGE>,
223
-                 'can_share': <SHARE_PERMISSION>, ...}, ...
224
-            ]}
225
-
226
-        """
227
-        try:
228
-            members = registry.get_member_images(req.context, id)
229
-        except exception.NotFound as e:
230
-            LOG.debug(encodeutils.exception_to_unicode(e))
231
-            raise webob.exc.HTTPNotFound(explanation=e.msg)
232
-        except exception.Forbidden as e:
233
-            LOG.debug(encodeutils.exception_to_unicode(e))
234
-            raise webob.exc.HTTPForbidden(explanation=e.msg)
235
-        return dict(shared_images=members)
236
-
237
-    def _update_store_acls(self, req, image_id):
238
-        image_meta = self.get_image_meta_or_404(req, image_id)
239
-        location_uri = image_meta.get('location')
240
-        public = image_meta.get('is_public')
241
-        self.update_store_acls(req, image_id, location_uri, public)
242
-
243
-
244
-def create_resource():
245
-    """Image members resource factory method"""
246
-    deserializer = wsgi.JSONRequestDeserializer()
247
-    serializer = wsgi.JSONResponseSerializer()
248
-    return wsgi.Resource(Controller(), deserializer, serializer)

+ 1
- 79
glance/api/v1/router.py View File

@@ -14,8 +14,6 @@
14 14
 #    under the License.
15 15
 
16 16
 
17
-from glance.api.v1 import images
18
-from glance.api.v1 import members
19 17
 from glance.common import wsgi
20 18
 
21 19
 
@@ -26,84 +24,8 @@ class API(wsgi.Router):
26 24
     def __init__(self, mapper):
27 25
         reject_method_resource = wsgi.Resource(wsgi.RejectMethodController())
28 26
 
29
-        images_resource = images.create_resource()
30
-
31 27
         mapper.connect("/",
32
-                       controller=images_resource,
33
-                       action="index")
34
-        mapper.connect("/images",
35
-                       controller=images_resource,
36
-                       action='index',
37
-                       conditions={'method': ['GET']})
38
-        mapper.connect("/images",
39
-                       controller=images_resource,
40
-                       action='create',
41
-                       conditions={'method': ['POST']})
42
-        mapper.connect("/images",
43
-                       controller=reject_method_resource,
44
-                       action='reject',
45
-                       allowed_methods='GET, POST')
46
-        mapper.connect("/images/detail",
47
-                       controller=images_resource,
48
-                       action='detail',
49
-                       conditions={'method': ['GET', 'HEAD']})
50
-        mapper.connect("/images/detail",
51
-                       controller=reject_method_resource,
52
-                       action='reject',
53
-                       allowed_methods='GET, HEAD')
54
-        mapper.connect("/images/{id}",
55
-                       controller=images_resource,
56
-                       action="meta",
57
-                       conditions=dict(method=["HEAD"]))
58
-        mapper.connect("/images/{id}",
59
-                       controller=images_resource,
60
-                       action="show",
61
-                       conditions=dict(method=["GET"]))
62
-        mapper.connect("/images/{id}",
63
-                       controller=images_resource,
64
-                       action="update",
65
-                       conditions=dict(method=["PUT"]))
66
-        mapper.connect("/images/{id}",
67
-                       controller=images_resource,
68
-                       action="delete",
69
-                       conditions=dict(method=["DELETE"]))
70
-        mapper.connect("/images/{id}",
71
-                       controller=reject_method_resource,
72
-                       action='reject',
73
-                       allowed_methods='GET, HEAD, PUT, DELETE')
74
-
75
-        members_resource = members.create_resource()
76
-
77
-        mapper.connect("/images/{image_id}/members",
78
-                       controller=members_resource,
79
-                       action="index",
80
-                       conditions={'method': ['GET']})
81
-        mapper.connect("/images/{image_id}/members",
82
-                       controller=members_resource,
83
-                       action="update_all",
84
-                       conditions=dict(method=["PUT"]))
85
-        mapper.connect("/images/{image_id}/members",
86
-                       controller=reject_method_resource,
87
-                       action='reject',
88
-                       allowed_methods='GET, PUT')
89
-        mapper.connect("/images/{image_id}/members/{id}",
90
-                       controller=members_resource,
91
-                       action="show",
92
-                       conditions={'method': ['GET']})
93
-        mapper.connect("/images/{image_id}/members/{id}",
94
-                       controller=members_resource,
95
-                       action="update",
96
-                       conditions={'method': ['PUT']})
97
-        mapper.connect("/images/{image_id}/members/{id}",
98
-                       controller=members_resource,
99
-                       action="delete",
100
-                       conditions={'method': ['DELETE']})
101
-        mapper.connect("/images/{image_id}/members/{id}",
102 28
                        controller=reject_method_resource,
103
-                       action='reject',
104
-                       allowed_methods='GET, PUT, DELETE')
105
-        mapper.connect("/shared-images/{id}",
106
-                       controller=members_resource,
107
-                       action="index_shared_images")
29
+                       action="reject")
108 30
 
109 31
         super(API, self).__init__(mapper)

+ 1
- 15
glance/api/versions.py View File

@@ -20,7 +20,7 @@ from six.moves import http_client
20 20
 import webob.dec
21 21
 
22 22
 from glance.common import wsgi
23
-from glance.i18n import _, _LW
23
+from glance.i18n import _
24 24
 
25 25
 
26 26
 versions_opts = [
@@ -82,20 +82,6 @@ class Controller(object):
82 82
                 build_version_object(2.1, 'v2', 'SUPPORTED'),
83 83
                 build_version_object(2.0, 'v2', 'SUPPORTED'),
84 84
             ])
85
-        if CONF.enable_v1_api:
86
-            LOG.warn(_LW('The Images (Glance) v1 API is deprecated and will '
87
-                         'be removed on or after the Pike release, following '
88
-                         'the standard OpenStack deprecation policy. '
89
-                         'Currently, the solution is to set '
90
-                         'enable_v1_api=False and enable_v2_api=True in your '
91
-                         'glance-api.conf file. Once those options are '
92
-                         'removed from the code, Images (Glance) v2 API will '
93
-                         'be switched on by default and will be the only '
94
-                         'option to deploy and use.'))
95
-            version_objs.extend([
96
-                build_version_object(1.1, 'v1', 'DEPRECATED'),
97
-                build_version_object(1.0, 'v1', 'DEPRECATED'),
98
-            ])
99 85
 
100 86
         status = explicit and http_client.OK or http_client.MULTIPLE_CHOICES
101 87
         response = webob.Response(request=req,

+ 0
- 490
glance/cmd/cache_manage.py View File

@@ -1,490 +0,0 @@
1
-#!/usr/bin/env python
2
-
3
-# Copyright 2011 OpenStack Foundation
4
-# All Rights Reserved.
5
-#
6
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7
-#    not use this file except in compliance with the License. You may obtain
8
-#    a copy of the License at
9
-#
10
-#         http://www.apache.org/licenses/LICENSE-2.0
11
-#
12
-#    Unless required by applicable law or agreed to in writing, software
13
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
-#    License for the specific language governing permissions and limitations
16
-#    under the License.
17
-
18
-"""
19
-A simple cache management utility for Glance.
20
-"""
21
-from __future__ import print_function
22
-
23
-import argparse
24
-import collections
25
-import datetime
26
-import functools
27
-import os
28
-import sys
29
-import time
30
-
31
-from oslo_utils import encodeutils
32
-import prettytable
33
-
34
-from six.moves import input
35
-
36
-# If ../glance/__init__.py exists, add ../ to Python search path, so that
37
-# it will override what happens to be installed in /usr/(local/)lib/python...
38
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
39
-                                   os.pardir,
40
-                                   os.pardir))
41
-if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')):
42
-    sys.path.insert(0, possible_topdir)
43
-
44
-from glance.common import exception
45
-import glance.image_cache.client
46
-from glance.version import version_info as version
47
-
48
-
49
-SUCCESS = 0
50
-FAILURE = 1
51
-
52
-
53
-def catch_error(action):
54
-    """Decorator to provide sensible default error handling for actions."""
55
-    def wrap(func):
56
-        @functools.wraps(func)
57
-        def wrapper(*args, **kwargs):
58
-            try:
59
-                ret = func(*args, **kwargs)
60
-                return SUCCESS if ret is None else ret
61
-            except exception.NotFound:
62
-                options = args[0]
63
-                print("Cache management middleware not enabled on host %s" %
64
-                      options.host)
65
-                return FAILURE
66
-            except exception.Forbidden:
67
-                print("Not authorized to make this request.")
68
-                return FAILURE
69
-            except Exception as e:
70
-                options = args[0]
71
-                if options.debug:
72
-                    raise
73
-                print("Failed to %s. Got error:" % action)
74
-                pieces = encodeutils.exception_to_unicode(e).split('\n')
75
-                for piece in pieces:
76
-                    print(piece)
77
-                return FAILURE
78
-
79
-        return wrapper
80
-    return wrap
81
-
82
-
83
-@catch_error('show cached images')
84
-def list_cached(args):
85
-    """%(prog)s list-cached [options]
86
-
87
-    List all images currently cached.
88
-    """
89
-    client = get_client(args)
90
-    images = client.get_cached_images()
91
-    if not images:
92
-        print("No cached images.")
93
-        return SUCCESS
94
-
95
-    print("Found %d cached images..." % len(images))
96
-
97
-    pretty_table = prettytable.PrettyTable(("ID",
98
-                                            "Last Accessed (UTC)",
99
-                                            "Last Modified (UTC)",
100
-                                            "Size",
101
-                                            "Hits"))
102
-    pretty_table.align['Size'] = "r"
103
-    pretty_table.align['Hits'] = "r"
104
-
105
-    for image in images:
106
-        last_accessed = image['last_accessed']
107
-        if last_accessed == 0:
108
-            last_accessed = "N/A"
109
-        else:
110
-            last_accessed = datetime.datetime.utcfromtimestamp(
111
-                last_accessed).isoformat()
112
-
113
-        pretty_table.add_row((
114
-            image['image_id'],
115
-            last_accessed,
116
-            datetime.datetime.utcfromtimestamp(
117
-                image['last_modified']).isoformat(),
118
-            image['size'],
119
-            image['hits']))
120
-
121
-    print(pretty_table.get_string())
122
-    return SUCCESS
123
-
124
-
125
-@catch_error('show queued images')
126
-def list_queued(args):
127
-    """%(prog)s list-queued [options]
128
-
129
-    List all images currently queued for caching.
130
-    """
131
-    client = get_client(args)
132
-    images = client.get_queued_images()
133
-    if not images:
134
-        print("No queued images.")
135
-        return SUCCESS
136
-
137
-    print("Found %d queued images..." % len(images))
138
-
139
-    pretty_table = prettytable.PrettyTable(("ID",))
140
-
141
-    for image in images:
142
-        pretty_table.add_row((image,))
143
-
144
-    print(pretty_table.get_string())
145
-
146
-
147
-@catch_error('queue the specified image for caching')
148
-def queue_image(args):
149
-    """%(prog)s queue-image <IMAGE_ID> [options]
150
-
151
-    Queues an image for caching.
152
-    """
153
-    if len(args.command) == 2:
154
-        image_id = args.command[1]
155
-    else:
156
-        print("Please specify one and only ID of the image you wish to ")
157
-        print("queue from the cache as the first argument")
158
-        return FAILURE
159
-
160
-    if (not args.force and
161
-        not user_confirm("Queue image %(image_id)s for caching?" %
162
-                         {'image_id': image_id}, default=False)):
163
-        return SUCCESS
164
-
165
-    client = get_client(args)
166
-    client.queue_image_for_caching(image_id)
167
-
168
-    if args.verbose:
169
-        print("Queued image %(image_id)s for caching" %
170
-              {'image_id': image_id})
171
-
172
-    return SUCCESS
173
-
174
-
175
-@catch_error('delete the specified cached image')
176
-def delete_cached_image(args):
177
-    """%(prog)s delete-cached-image <IMAGE_ID> [options]
178
-
179
-    Deletes an image from the cache.
180
-    """
181
-    if len(args.command) == 2:
182
-        image_id = args.command[1]
183
-    else:
184
-        print("Please specify one and only ID of the image you wish to ")
185
-        print("delete from the cache as the first argument")
186
-        return FAILURE
187
-
188
-    if (not args.force and
189
-        not user_confirm("Delete cached image %(image_id)s?" %
190
-                         {'image_id': image_id}, default=False)):
191
-        return SUCCESS
192
-
193
-    client = get_client(args)
194
-    client.delete_cached_image(image_id)
195
-
196
-    if args.verbose:
197
-        print("Deleted cached image %(image_id)s" % {'image_id': image_id})
198
-
199
-    return SUCCESS
200
-
201
-
202
-@catch_error('Delete all cached images')
203
-def delete_all_cached_images(args):
204
-    """%(prog)s delete-all-cached-images [options]
205
-
206
-    Remove all images from the cache.
207
-    """
208
-    if (not args.force and
209
-            not user_confirm("Delete all cached images?", default=False)):
210
-        return SUCCESS
211
-
212
-    client = get_client(args)
213
-    num_deleted = client.delete_all_cached_images()
214
-
215
-    if args.verbose:
216
-        print("Deleted %(num_deleted)s cached images" %
217
-              {'num_deleted': num_deleted})
218
-
219
-    return SUCCESS
220
-
221
-
222
-@catch_error('delete the specified queued image')
223
-def delete_queued_image(args):
224
-    """%(prog)s delete-queued-image <IMAGE_ID> [options]
225
-
226
-    Deletes an image from the cache.
227
-    """
228
-    if len(args.command) == 2:
229
-        image_id = args.command[1]
230
-    else:
231
-        print("Please specify one and only ID of the image you wish to ")
232
-        print("delete from the cache as the first argument")
233
-        return FAILURE
234
-
235
-    if (not args.force and
236
-        not user_confirm("Delete queued image %(image_id)s?" %
237
-                         {'image_id': image_id}, default=False)):
238
-        return SUCCESS
239
-
240
-    client = get_client(args)
241
-    client.delete_queued_image(image_id)
242
-
243
-    if args.verbose:
244
-        print("Deleted queued image %(image_id)s" % {'image_id': image_id})
245
-
246
-    return SUCCESS
247
-
248
-
249
-@catch_error('Delete all queued images')
250
-def delete_all_queued_images(args):
251
-    """%(prog)s delete-all-queued-images [options]
252
-
253
-    Remove all images from the cache queue.
254
-    """
255
-    if (not args.force and
256
-            not user_confirm("Delete all queued images?", default=False)):
257
-        return SUCCESS
258
-
259
-    client = get_client(args)
260
-    num_deleted = client.delete_all_queued_images()
261
-
262
-    if args.verbose:
263
-        print("Deleted %(num_deleted)s queued images" %
264
-              {'num_deleted': num_deleted})
265
-
266
-    return SUCCESS
267
-
268
-
269
-def get_client(options):
270
-    """Return a new client object to a Glance server.
271
-
272
-    specified by the --host and --port options
273
-    supplied to the CLI
274
-    """
275
-    return glance.image_cache.client.get_client(
276
-        host=options.host,
277
-        port=options.port,
278
-        username=options.os_username,
279
-        password=options.os_password,
280
-        tenant=options.os_tenant_name,
281
-        auth_url=options.os_auth_url,
282
-        auth_strategy=options.os_auth_strategy,
283
-        auth_token=options.os_auth_token,
284
-        region=options.os_region_name,
285
-        insecure=options.insecure)
286
-
287
-
288
-def env(*vars, **kwargs):
289
-    """Search for the first defined of possibly many env vars.
290
-
291
-    Returns the first environment variable defined in vars, or
292
-    returns the default defined in kwargs.
293
-    """
294
-    for v in vars:
295
-        value = os.environ.get(v)
296
-        if value:
297
-            return value
298
-    return kwargs.get('default', '')
299
-
300
-
301
-def print_help(args):
302
-    """
303
-    Print help specific to a command
304
-    """
305
-    command = lookup_command(args.command[1])
306
-    print(command.__doc__ % {'prog': os.path.basename(sys.argv[0])})
307
-
308
-
309
-def parse_args(parser):
310
-    """Set up the CLI and config-file options that may be
311
-    parsed and program commands.
312
-
313
-    :param parser: The option parser
314
-    """
315
-    parser.add_argument('command', default='help', nargs='*',
316
-                        help='The command to execute')
317
-    parser.add_argument('-v', '--verbose', default=False, action="store_true",
318
-                        help="Print more verbose output.")
319
-    parser.add_argument('-d', '--debug', default=False, action="store_true",
320
-                        help="Print debugging output.")
321
-    parser.add_argument('-H', '--host', metavar="ADDRESS", default="0.0.0.0",
322
-                        help="Address of Glance API host.")
323
-    parser.add_argument('-p', '--port', dest="port", metavar="PORT",
324
-                        type=int, default=9292,
325
-                        help="Port the Glance API host listens on.")
326
-    parser.add_argument('-k', '--insecure', dest="insecure",
327
-                        default=False, action="store_true",
328
-                        help='Explicitly allow glance to perform "insecure" '
329
-                             "SSL (https) requests. The server's certificate "
330
-                             "will not be verified against any certificate "
331
-                             "authorities. This option should be used with "
332
-                             "caution.")
333
-    parser.add_argument('-f', '--force', dest="force",
334
-                        default=False, action="store_true",
335
-                        help="Prevent select actions from requesting "
336
-                             "user confirmation.")
337
-
338
-    parser.add_argument('--os-auth-token',
339
-                        dest='os_auth_token',
340
-                        default=env('OS_AUTH_TOKEN'),
341
-                        help='Defaults to env[OS_AUTH_TOKEN].')
342
-    parser.add_argument('-A', '--os_auth_token', '--auth_token',
343
-                        dest='os_auth_token',
344
-                        help=argparse.SUPPRESS)
345
-
346
-    parser.add_argument('--os-username',
347
-                        dest='os_username',
348
-                        default=env('OS_USERNAME'),
349
-                        help='Defaults to env[OS_USERNAME].')
350
-    parser.add_argument('-I', '--os_username',
351
-                        dest='os_username',
352
-                        help=argparse.SUPPRESS)
353
-
354
-    parser.add_argument('--os-password',
355
-                        dest='os_password',
356
-                        default=env('OS_PASSWORD'),
357
-                        help='Defaults to env[OS_PASSWORD].')
358
-    parser.add_argument('-K', '--os_password',
359
-                        dest='os_password',
360
-                        help=argparse.SUPPRESS)
361
-
362
-    parser.add_argument('--os-region-name',
363
-                        dest='os_region_name',
364
-                        default=env('OS_REGION_NAME'),
365
-                        help='Defaults to env[OS_REGION_NAME].')
366
-    parser.add_argument('-R', '--os_region_name',
367
-                        dest='os_region_name',
368
-                        help=argparse.SUPPRESS)
369
-
370
-    parser.add_argument('--os-tenant-id',
371
-                        dest='os_tenant_id',
372
-                        default=env('OS_TENANT_ID'),
373
-                        help='Defaults to env[OS_TENANT_ID].')
374
-    parser.add_argument('--os_tenant_id',
375
-                        dest='os_tenant_id',
376
-                        help=argparse.SUPPRESS)
377
-
378
-    parser.add_argument('--os-tenant-name',
379
-                        dest='os_tenant_name',
380
-                        default=env('OS_TENANT_NAME'),
381
-                        help='Defaults to env[OS_TENANT_NAME].')
382
-    parser.add_argument('-T', '--os_tenant_name',
383
-                        dest='os_tenant_name',
384
-                        help=argparse.SUPPRESS)
385
-
386
-    parser.add_argument('--os-auth-url',
387
-                        default=env('OS_AUTH_URL'),
388
-                        help='Defaults to env[OS_AUTH_URL].')
389
-    parser.add_argument('-N', '--os_auth_url',
390
-                        dest='os_auth_url',
391
-                        help=argparse.SUPPRESS)
392
-
393
-    parser.add_argument('-S', '--os_auth_strategy', dest="os_auth_strategy",
394
-                        metavar="STRATEGY",
395
-                        help="Authentication strategy (keystone or noauth).")
396
-
397
-    version_string = version.cached_version_string()
398
-    parser.add_argument('--version', action='version',
399
-                        version=version_string)
400
-
401
-    return parser.parse_args()
402
-
403
-
404
-CACHE_COMMANDS = collections.OrderedDict()
405
-CACHE_COMMANDS['help'] = (
406
-    print_help, 'Output help for one of the commands below')
407
-CACHE_COMMANDS['list-cached'] = (
408
-    list_cached, 'List all images currently cached')
409
-CACHE_COMMANDS['list-queued'] = (
410
-    list_queued, 'List all images currently queued for caching')
411
-CACHE_COMMANDS['queue-image'] = (
412
-    queue_image, 'Queue an image for caching')
413
-CACHE_COMMANDS['delete-cached-image'] = (
414
-    delete_cached_image, 'Purges an image from the cache')
415
-CACHE_COMMANDS['delete-all-cached-images'] = (
416
-    delete_all_cached_images, 'Removes all images from the cache')
417
-CACHE_COMMANDS['delete-queued-image'] = (
418
-    delete_queued_image, 'Deletes an image from the cache queue')
419
-CACHE_COMMANDS['delete-all-queued-images'] = (
420
-    delete_all_queued_images, 'Deletes all images from the cache queue')
421
-
422
-
423
-def _format_command_help():
424
-    """Formats the help string for subcommands."""
425
-    help_msg = "Commands:\n\n"
426
-
427
-    for command, info in CACHE_COMMANDS.items():
428
-        if command == 'help':
429
-            command = 'help <command>'
430
-        help_msg += "    %-28s%s\n\n" % (command, info[1])
431
-
432
-    return help_msg
433
-
434
-
435
-def lookup_command(command_name):
436
-    try:
437
-        command = CACHE_COMMANDS[command_name]
438
-        return command[0]
439
-    except KeyError:
440
-        print('\nError: "%s" is not a valid command.\n' % command_name)
441
-        print(_format_command_help())
442
-        sys.exit("Unknown command: %(cmd_name)s" % {'cmd_name': command_name})
443
-
444
-
445
-def user_confirm(prompt, default=False):
446
-    """Yes/No question dialog with user.
447
-
448
-    :param prompt: question/statement to present to user (string)
449
-    :param default: boolean value to return if empty string
450
-                    is received as response to prompt
451
-
452
-    """
453
-    if default:
454
-        prompt_default = "[Y/n]"
455
-    else:
456
-        prompt_default = "[y/N]"
457
-
458
-    answer = input("%s %s " % (prompt, prompt_default))
459
-
460
-    if answer == "":
461
-        return default
462
-    else:
463
-        return answer.lower() in ("yes", "y")
464
-
465
-
466
-def main():
467
-    parser = argparse.ArgumentParser(
468
-        description=_format_command_help(),
469
-        formatter_class=argparse.RawDescriptionHelpFormatter)
470
-    args = parse_args(parser)
471
-
472
-    if args.command[0] == 'help' and len(args.command) == 1:
473
-        parser.print_help()
474
-        return
475
-
476
-    # Look up the command to run
477
-    command = lookup_command(args.command[0])
478
-
479
-    try:
480
-        start_time = time.time()
481
-        result = command(args)
482
-        end_time = time.time()
483
-        if args.verbose:
484
-            print("Completed in %-0.4f sec." % (end_time - start_time))
485
-        sys.exit(result)
486
-    except (RuntimeError, NotImplementedError) as e:
487
-        sys.exit("ERROR: %s" % e)
488
-
489
-if __name__ == '__main__':
490
-    main()

+ 1
- 71
glance/common/config.py View File

@@ -454,50 +454,6 @@ Possible values:
454 454
 Related options:
455 455
     * None
456 456
 
457
-""")),
458
-    # NOTE(nikhil): Even though deprecated, the configuration option
459
-    # ``enable_v1_api`` is set to True by default on purpose. Having it enabled
460
-    # helps the projects that haven't been able to fully move to v2 yet by
461
-    # keeping the devstack setup to use glance v1 as well. We need to switch it
462
-    # to False by default soon after Newton is cut so that we can identify the
463
-    # projects that haven't moved to v2 yet and start having some interesting
464
-    # conversations with them. Switching to False in Newton may result into
465
-    # destabilizing the gate and affect the release.
466
-    cfg.BoolOpt('enable_v1_api',
467
-                default=True,
468
-                deprecated_reason=_DEPRECATE_GLANCE_V1_MSG,
469
-                deprecated_since='Newton',
470
-                help=_("""
471
-Deploy the v1 OpenStack Images API.
472
-
473
-When this option is set to ``True``, Glance service will respond to
474
-requests on registered endpoints conforming to the v1 OpenStack
475
-Images API.
476
-
477
-NOTES:
478
-    * If this option is enabled, then ``enable_v1_registry`` must
479
-      also be set to ``True`` to enable mandatory usage of Registry
480
-      service with v1 API.
481
-
482
-    * If this option is disabled, then the ``enable_v1_registry``
483
-      option, which is enabled by default, is also recommended
484
-      to be disabled.
485
-
486
-    * This option is separate from ``enable_v2_api``, both v1 and v2
487
-      OpenStack Images API can be deployed independent of each
488
-      other.
489
-
490
-    * If deploying only the v2 Images API, this option, which is
491
-      enabled by default, should be disabled.
492
-
493
-Possible values:
494
-    * True
495
-    * False
496
-
497
-Related options:
498
-    * enable_v1_registry
499
-    * enable_v2_api
500
-
501 457
 """)),
502 458
     cfg.BoolOpt('enable_v2_api',
503 459
                 default=True,
@@ -523,20 +479,12 @@ NOTES:
523 479
       option, which is enabled by default, is also recommended
524 480
       to be disabled.
525 481
 
526
-    * This option is separate from ``enable_v1_api``, both v1 and v2
527
-      OpenStack Images API can be deployed independent of each
528
-      other.
529
-
530
-    * If deploying only the v1 Images API, this option, which is
531
-      enabled by default, should be disabled.
532
-
533 482
 Possible values:
534 483
     * True
535 484
     * False
536 485
 
537 486
 Related options:
538 487
     * enable_v2_registry
539
-    * enable_v1_api
540 488
 
541 489
 """)),
542 490
     cfg.BoolOpt('enable_v1_registry',
@@ -544,25 +492,7 @@ Related options:
544 492
                 deprecated_reason=_DEPRECATE_GLANCE_V1_MSG,
545 493
                 deprecated_since='Newton',
546 494
                 help=_("""
547
-Deploy the v1 API Registry service.
548
-
549
-When this option is set to ``True``, the Registry service
550
-will be enabled in Glance for v1 API requests.
551
-
552
-NOTES:
553
-    * Use of Registry is mandatory in v1 API, so this option must
554
-      be set to ``True`` if the ``enable_v1_api`` option is enabled.
555
-
556
-    * If deploying only the v2 OpenStack Images API, this option,
557
-      which is enabled by default, should be disabled.
558
-
559
-Possible values:
560
-    * True
561
-    * False
562
-
563
-Related options:
564
-    * enable_v1_api
565
-
495
+                    DEPRECATED FOR REMOVAL
566 496
 """)),
567 497
     cfg.BoolOpt('enable_v2_registry',
568 498
                 default=True,

+ 1
- 0
glance/common/store_utils.py View File

@@ -27,6 +27,7 @@ from glance import scrubber
27 27
 LOG = logging.getLogger(__name__)
28 28
 
29 29
 CONF = cfg.CONF
30
+CONF.import_opt('use_user_token', 'glance.registry.client')
30 31
 
31 32
 RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
32 33
 

+ 0
- 132
glance/image_cache/client.py View File

@@ -1,132 +0,0 @@
1
-# Copyright 2012 OpenStack Foundation
2
-# All Rights Reserved.
3
-#
4
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
-#    not use this file except in compliance with the License. You may obtain
6
-#    a copy of the License at
7
-#
8
-#         http://www.apache.org/licenses/LICENSE-2.0
9
-#
10
-#    Unless required by applicable law or agreed to in writing, software
11
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
-#    License for the specific language governing permissions and limitations
14
-#    under the License.
15
-
16
-import os
17
-
18
-from oslo_serialization import jsonutils as json
19
-
20
-from glance.common import client as base_client
21
-from glance.common import exception
22
-from glance.i18n import _
23
-
24
-
25
-class CacheClient(base_client.BaseClient):
26
-
27
-    DEFAULT_PORT = 9292
28
-    DEFAULT_DOC_ROOT = '/v1'
29
-
30
-    def delete_cached_image(self, image_id):
31
-        """
32
-        Delete a specified image from the cache
33
-        """
34
-        self.do_request("DELETE", "/cached_images/%s" % image_id)
35
-        return True
36
-
37
-    def get_cached_images(self, **kwargs):
38
-        """
39
-        Returns a list of images stored in the image cache.
40
-        """
41
-        res = self.do_request("GET", "/cached_images")
42
-        data = json.loads(res.read())['cached_images']
43
-        return data
44
-
45
-    def get_queued_images(self, **kwargs):
46
-        """
47
-        Returns a list of images queued for caching
48
-        """
49
-        res = self.do_request("GET", "/queued_images")
50
-        data = json.loads(res.read())['queued_images']
51
-        return data
52
-
53
-    def delete_all_cached_images(self):
54
-        """
55
-        Delete all cached images
56
-        """
57
-        res = self.do_request("DELETE", "/cached_images")
58
-        data = json.loads(res.read())
59
-        num_deleted = data['num_deleted']
60
-        return num_deleted
61
-
62
-    def queue_image_for_caching(self, image_id):
63
-        """
64
-        Queue an image for prefetching into cache
65
-        """
66
-        self.do_request("PUT", "/queued_images/%s" % image_id)
67
-        return True
68
-
69
-    def delete_queued_image(self, image_id):
70
-        """
71
-        Delete a specified image from the cache queue
72
-        """
73
-        self.do_request("DELETE", "/queued_images/%s" % image_id)
74
-        return True
75
-
76
-    def delete_all_queued_images(self):
77
-        """
78
-        Delete all queued images
79
-        """
80
-        res = self.do_request("DELETE", "/queued_images")
81
-        data = json.loads(res.read())
82
-        num_deleted = data['num_deleted']
83
-        return num_deleted
84
-
85
-
86
-def get_client(host, port=None, timeout=None, use_ssl=False, username=None,
87
-               password=None, tenant=None,
88
-               auth_url=None, auth_strategy=None,
89
-               auth_token=None, region=None,
90
-               is_silent_upload=False, insecure=False):
91
-    """
92
-    Returns a new client Glance client object based on common kwargs.
93
-    If an option isn't specified falls back to common environment variable
94
-    defaults.
95
-    """
96
-
97
-    if auth_url or os.getenv('OS_AUTH_URL'):
98
-        force_strategy = 'keystone'
99
-    else:
100
-        force_strategy = None
101
-
102
-    creds = {
103
-        'username': username or
104
-        os.getenv('OS_AUTH_USER', os.getenv('OS_USERNAME')),
105
-        'password': password or
106
-        os.getenv('OS_AUTH_KEY', os.getenv('OS_PASSWORD')),
107
-        'tenant': tenant or
108
-        os.getenv('OS_AUTH_TENANT', os.getenv('OS_TENANT_NAME')),
109
-        'auth_url': auth_url or
110
-        os.getenv('OS_AUTH_URL'),
111
-        'strategy': force_strategy or
112
-        auth_strategy or
113
-        os.getenv('OS_AUTH_STRATEGY', 'noauth'),
114
-        'region': region or
115
-        os.getenv('OS_REGION_NAME'),
116
-    }
117
-
118
-    if creds['strategy'] == 'keystone' and not creds['auth_url']:
119
-        msg = _("--os_auth_url option or OS_AUTH_URL environment variable "
120
-                "required when keystone authentication strategy is enabled\n")
121
-        raise exception.ClientConfigurationError(msg)
122
-
123
-    return CacheClient(
124
-        host=host,
125
-        port=port,
126
-        timeout=timeout,
127
-        use_ssl=use_ssl,
128
-        auth_token=auth_token or
129
-        os.getenv('OS_TOKEN'),
130
-        creds=creds,
131
-        insecure=insecure,
132
-        configure_via_auth=False)

+ 0
- 3
glance/tests/functional/__init__.py View File

@@ -74,9 +74,7 @@ class Server(object):
74 74
         self.show_image_direct_url = False
75 75
         self.show_multiple_locations = False
76 76
         self.property_protection_file = ''
77
-        self.enable_v1_api = True
78 77
         self.enable_v2_api = True
79
-        self.enable_v1_registry = True
80 78
         self.enable_v2_registry = True
81 79
         self.needs_database = False
82 80
         self.log_file = None
@@ -346,7 +344,6 @@ sql_connection = %(sql_connection)s
346 344
 show_image_direct_url = %(show_image_direct_url)s
347 345
 show_multiple_locations = %(show_multiple_locations)s
348 346
 user_storage_quota = %(user_storage_quota)s
349
-enable_v1_api = %(enable_v1_api)s
350 347
 enable_v2_api = %(enable_v2_api)s
351 348
 lock_path = %(lock_path)s
352 349
 property_protection_file = %(property_protection_file)s

+ 12
- 4
glance/tests/functional/serial/test_scrubber.py View File

@@ -78,8 +78,10 @@ class TestScrubber(functional.FunctionalTest):
78 78
         scrubs them
79 79
         """
80 80
         self.cleanup()
81
+        kwargs = self.__dict__.copy()
82
+        kwargs['use_user_token'] = True
81 83
         self.start_servers(delayed_delete=True, daemon=True,
82
-                           metadata_encryption_key='')
84
+                           metadata_encryption_key='', **kwargs)
83 85
         path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
84 86
         response, content = self._send_create_image_http_request(path)
85 87
         self.assertEqual(http_client.CREATED, response.status)
@@ -112,8 +114,10 @@ class TestScrubber(functional.FunctionalTest):
112 114
         daemon mode
113 115
         """
114 116
         self.cleanup()
117
+        kwargs = self.__dict__.copy()
118
+        kwargs['use_user_token'] = True
115 119
         self.start_servers(delayed_delete=True, daemon=False,
116
-                           metadata_encryption_key='')
120
+                           metadata_encryption_key='', **kwargs)
117 121
         path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
118 122
         response, content = self._send_create_image_http_request(path)
119 123
         self.assertEqual(http_client.CREATED, response.status)
@@ -159,8 +163,10 @@ class TestScrubber(functional.FunctionalTest):
159 163
 
160 164
         # Start servers.
161 165
         self.cleanup()
166
+        kwargs = self.__dict__.copy()
167
+        kwargs['use_user_token'] = True
162 168
         self.start_servers(delayed_delete=True, daemon=False,
163
-                           default_store='file')
169
+                           default_store='file', **kwargs)
164 170
 
165 171
         # Check that we are using a file backend.
166 172
         self.assertEqual(self.api_server.default_store, 'file')
@@ -235,8 +241,10 @@ class TestScrubber(functional.FunctionalTest):
235 241
 
236 242
     def test_scrubber_restore_image(self):
237 243
         self.cleanup()
244
+        kwargs = self.__dict__.copy()
245
+        kwargs['use_user_token'] = True
238 246
         self.start_servers(delayed_delete=True, daemon=False,
239
-                           metadata_encryption_key='')
247
+                           metadata_encryption_key='', **kwargs)
240 248
         path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
241 249
         response, content = self._send_create_image_http_request(path)
242 250
         self.assertEqual(http_client.CREATED, response.status)

+ 1
- 149
glance/tests/functional/test_api.py View File

@@ -22,25 +22,6 @@ from six.moves import http_client
22 22
 
23 23
 from glance.tests import functional
24 24
 
25
-# TODO(rosmaita): all the EXPERIMENTAL stuff in this file can be ripped out
26
-# when v2.6 becomes CURRENT in Queens
27
-
28
-
29
-def _generate_v1_versions(url):
30
-    v1_versions = {'versions': [
31
-        {
32
-            'id': 'v1.1',
33
-            'status': 'DEPRECATED',
34
-            'links': [{'rel': 'self', 'href': url % '1'}],
35
-        },
36
-        {
37
-            'id': 'v1.0',
38
-            'status': 'DEPRECATED',
39
-            'links': [{'rel': 'self', 'href': url % '1'}],
40
-        },
41
-    ]}
42
-    return v1_versions
43
-
44 25
 
45 26
 def _generate_v2_versions(url):
46 27
     version_list = []
@@ -86,9 +67,8 @@ def _generate_v2_versions(url):
86 67
 
87 68
 
88 69
 def _generate_all_versions(url):
89
-    v1 = _generate_v1_versions(url)
90 70
     v2 = _generate_v2_versions(url)
91
-    all_versions = {'versions': v2['versions'] + v1['versions']}
71
+    all_versions = {'versions': v2['versions']}
92 72
     return all_versions
93 73
 
94 74
 
@@ -96,7 +76,6 @@ class TestApiVersions(functional.FunctionalTest):
96 76
 
97 77
     def test_version_configurations(self):
98 78
         """Test that versioning is handled properly through all channels"""
99
-        # v1 and v2 api enabled
100 79
         self.start_servers(**self.__dict__.copy())
101 80
 
102 81
         url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
@@ -111,7 +90,6 @@ class TestApiVersions(functional.FunctionalTest):
111 90
         self.assertEqual(versions, content)
112 91
 
113 92
     def test_v2_api_configuration(self):
114
-        self.api_server.enable_v1_api = False
115 93
         self.api_server.enable_v2_api = True
116 94
         self.start_servers(**self.__dict__.copy())
117 95
 
@@ -126,22 +104,6 @@ class TestApiVersions(functional.FunctionalTest):
126 104
         content = jsonutils.loads(content_json.decode())
127 105
         self.assertEqual(versions, content)
128 106
 
129
-    def test_v1_api_configuration(self):
130
-        self.api_server.enable_v1_api = True
131
-        self.api_server.enable_v2_api = False
132
-        self.start_servers(**self.__dict__.copy())
133
-
134
-        url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
135
-        versions = _generate_v1_versions(url)
136
-
137
-        # Verify version choices returned.
138
-        path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
139
-        http = httplib2.Http()
140
-        response, content_json = http.request(path, 'GET')
141
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
142
-        content = jsonutils.loads(content_json.decode())
143
-        self.assertEqual(versions, content)
144
-
145 107
 
146 108
 class TestApiPaths(functional.FunctionalTest):
147 109
     def setUp(self):
@@ -165,26 +127,6 @@ class TestApiPaths(functional.FunctionalTest):
165 127
         content = jsonutils.loads(content_json.decode())
166 128
         self.assertEqual(self.versions, content)
167 129
 
168
-    def test_get_images_path(self):
169
-        """Assert GET /images with `no Accept:` header.
170
-        Verify version choices returned.
171
-        """
172
-        path = 'http://%s:%d/images' % ('127.0.0.1', self.api_port)
173
-        http = httplib2.Http()
174
-        response, content_json = http.request(path, 'GET')
175
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
176
-        content = jsonutils.loads(content_json.decode())
177
-        self.assertEqual(self.versions, content)
178
-
179
-    def test_get_v1_images_path(self):
180
-        """GET /v1/images with `no Accept:` header.
181
-        Verify empty images list returned.
182
-        """
183
-        path = 'http://%s:%d/v1/images' % ('127.0.0.1', self.api_port)
184
-        http = httplib2.Http()
185
-        response, content = http.request(path, 'GET')
186
-        self.assertEqual(http_client.OK, response.status)
187
-
188 130
     def test_get_root_path_with_unknown_header(self):
189 131
         """Assert GET / with Accept: unknown header
190 132
         Verify version choices returned. Verify message in API log about
@@ -198,49 +140,6 @@ class TestApiPaths(functional.FunctionalTest):
198 140
         content = jsonutils.loads(content_json.decode())
199 141
         self.assertEqual(self.versions, content)
200 142
 
201
-    def test_get_root_path_with_openstack_header(self):
202
-        """Assert GET / with an Accept: application/vnd.openstack.images-v1
203
-        Verify empty image list returned
204
-        """
205
-        path = 'http://%s:%d/images' % ('127.0.0.1', self.api_port)
206
-        http = httplib2.Http()
207
-        headers = {'Accept': 'application/vnd.openstack.images-v1'}
208
-        response, content = http.request(path, 'GET', headers=headers)
209
-        self.assertEqual(http_client.OK, response.status)
210
-        self.assertEqual(self.images_json, content.decode())
211
-
212
-    def test_get_images_path_with_openstack_header(self):
213
-        """Assert GET /images with a
214
-        `Accept: application/vnd.openstack.compute-v1` header.
215
-        Verify version choices returned. Verify message in API log
216
-        about unknown accept header.
217
-        """
218
-        path = 'http://%s:%d/images' % ('127.0.0.1', self.api_port)
219
-        http = httplib2.Http()
220
-        headers = {'Accept': 'application/vnd.openstack.compute-v1'}
221
-        response, content_json = http.request(path, 'GET', headers=headers)
222
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
223
-        content = jsonutils.loads(content_json.decode())
224
-        self.assertEqual(self.versions, content)
225
-
226
-    def test_get_v10_images_path(self):
227
-        """Assert GET /v1.0/images with no Accept: header
228
-        Verify version choices returned
229
-        """
230
-        path = 'http://%s:%d/v1.a/images' % ('127.0.0.1', self.api_port)
231
-        http = httplib2.Http()
232
-        response, content = http.request(path, 'GET')
233
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
234
-
235
-    def test_get_v1a_images_path(self):
236
-        """Assert GET /v1.a/images with no Accept: header
237
-        Verify version choices returned
238
-        """
239
-        path = 'http://%s:%d/v1.a/images' % ('127.0.0.1', self.api_port)
240
-        http = httplib2.Http()
241
-        response, content = http.request(path, 'GET')
242
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
243
-
244 143
     def test_get_va1_images_path(self):
245 144
         """Assert GET /va.1/images with no Accept: header
246 145
         Verify version choices returned
@@ -263,28 +162,6 @@ class TestApiPaths(functional.FunctionalTest):
263 162
         content = jsonutils.loads(content_json.decode())
264 163
         self.assertEqual(self.versions, content)
265 164
 
266
-    def test_get_versions_path_with_openstack_header(self):
267
-        """Assert GET /versions with the
268
-        `Accept: application/vnd.openstack.images-v1` header.
269
-        Verify version choices returned.
270
-        """
271
-        path = 'http://%s:%d/versions' % ('127.0.0.1', self.api_port)
272
-        http = httplib2.Http()
273
-        headers = {'Accept': 'application/vnd.openstack.images-v1'}
274
-        response, content_json = http.request(path, 'GET', headers=headers)
275
-        self.assertEqual(http_client.OK, response.status)
276
-        content = jsonutils.loads(content_json.decode())
277
-        self.assertEqual(self.versions, content)
278
-
279
-    def test_get_v1_versions_path(self):
280
-        """Assert GET /v1/versions with `no Accept:` header
281
-        Verify 404 returned
282
-        """
283
-        path = 'http://%s:%d/v1/versions' % ('127.0.0.1', self.api_port)
284
-        http = httplib2.Http()
285
-        response, content = http.request(path, 'GET')
286
-        self.assertEqual(http_client.NOT_FOUND, response.status)
287
-
288 165
     def test_get_versions_choices(self):
289 166
         """Verify version choices returned"""
290 167
         path = 'http://%s:%d/v10' % ('127.0.0.1', self.api_port)
@@ -293,28 +170,3 @@ class TestApiPaths(functional.FunctionalTest):
293 170
         self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
294 171
         content = jsonutils.loads(content_json.decode())
295 172
         self.assertEqual(self.versions, content)
296
-
297
-    def test_get_images_path_with_openstack_v2_header(self):
298
-        """Assert GET /images with a
299
-        `Accept: application/vnd.openstack.compute-v2` header.
300
-        Verify version choices returned. Verify message in API log
301
-        about unknown version in accept header.
302
-        """
303
-        path = 'http://%s:%d/images' % ('127.0.0.1', self.api_port)
304
-        http = httplib2.Http()
305
-        headers = {'Accept': 'application/vnd.openstack.images-v10'}
306
-        response, content_json = http.request(path, 'GET', headers=headers)
307
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
308
-        content = jsonutils.loads(content_json.decode())
309
-        self.assertEqual(self.versions, content)
310
-
311
-    def test_get_v12_images_path(self):
312
-        """Assert GET /v1.2/images with `no Accept:` header
313
-        Verify version choices returned
314
-        """
315
-        path = 'http://%s:%d/v1.2/images' % ('127.0.0.1', self.api_port)
316
-        http = httplib2.Http()
317
-        response, content_json = http.request(path, 'GET')
318
-        self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
319
-        content = jsonutils.loads(content_json.decode())
320
-        self.assertEqual(self.versions, content)

+ 0
- 358
glance/tests/functional/test_bin_glance_cache_manage.py View File

@@ -1,358 +0,0 @@
1
-# Copyright 2011 OpenStack Foundation
2
-# All Rights Reserved.
3
-#
4
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
-#    not use this file except in compliance with the License. You may obtain
6
-#    a copy of the License at
7
-#
8
-#         http://www.apache.org/licenses/LICENSE-2.0
9
-#
10
-#    Unless required by applicable law or agreed to in writing, software
11
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
-#    License for the specific language governing permissions and limitations
14
-#    under the License.
15
-
16
-"""Functional test case that utilizes the bin/glance-cache-manage CLI tool"""
17
-
18
-import datetime
19
-import hashlib
20
-import os
21
-import sys
22
-
23
-import httplib2
24
-from oslo_serialization import jsonutils
25
-from oslo_utils import units
26
-from six.moves import http_client
27
-# NOTE(jokke): simplified transition to py3, behaves like py2 xrange
28
-from six.moves import range
29
-
30
-from glance.tests import functional
31
-from glance.tests.utils import execute
32
-from glance.tests.utils import minimal_headers
33
-
34
-FIVE_KB = 5 * units.Ki
35
-
36
-
37
-class TestBinGlanceCacheManage(functional.FunctionalTest):
38
-    """Functional tests for the bin/glance CLI tool"""
39
-
40
-    def setUp(self):
41
-        self.image_cache_driver = "sqlite"
42
-
43
-        super(TestBinGlanceCacheManage, self).setUp()
44
-
45
-        self.api_server.deployment_flavor = "cachemanagement"
46
-
47
-        # NOTE(sirp): This is needed in case we are running the tests under an
48
-        # environment in which OS_AUTH_STRATEGY=keystone. The test server we
49
-        # spin up won't have keystone support, so we need to switch to the
50
-        # NoAuth strategy.
51
-        os.environ['OS_AUTH_STRATEGY'] = 'noauth'
52
-        os.environ['OS_AUTH_URL'] = ''
53
-
54
-    def add_image(self, name):
55
-        """
56
-        Adds an image with supplied name and returns the newly-created
57
-        image identifier.
58
-        """
59
-        image_data = b"*" * FIVE_KB
60
-        headers = minimal_headers(name)
61
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
62
-        http = httplib2.Http()
63
-        response, content = http.request(path, 'POST', headers=headers,
64
-                                         body=image_data)
65
-        self.assertEqual(http_client.CREATED, response.status)
66
-        data = jsonutils.loads(content)
67
-        self.assertEqual(hashlib.md5(image_data).hexdigest(),
68
-                         data['image']['checksum'])
69
-        self.assertEqual(FIVE_KB, data['image']['size'])
70
-        self.assertEqual(name, data['image']['name'])
71
-        self.assertTrue(data['image']['is_public'])
72
-        return data['image']['id']
73
-
74
-    def is_image_cached(self, image_id):
75
-        """
76
-        Return True if supplied image ID is cached, False otherwise
77
-        """
78
-        exe_cmd = '%s -m glance.cmd.cache_manage' % sys.executable
79
-        cmd = "%s --port=%d list-cached" % (exe_cmd, self.api_port)
80
-
81
-        exitcode, out, err = execute(cmd)
82
-
83
-        self.assertEqual(0, exitcode)
84
-        out = out.decode('utf-8')
85
-        return image_id in out
86
-
87
-    def iso_date(self, image_id):
88
-        """
89
-        Return True if supplied image ID is cached, False otherwise
90
-        """
91
-        exe_cmd = '%s -m glance.cmd.cache_manage' % sys.executable
92
-        cmd = "%s --port=%d list-cached" % (exe_cmd, self.api_port)
93
-
94
-        exitcode, out, err = execute(cmd)
95
-        out = out.decode('utf-8')
96
-
97
-        return datetime.datetime.utcnow().strftime("%Y-%m-%d") in out
98
-
99
-    def test_no_cache_enabled(self):
100
-        """
101
-        Test that cache index command works
102
-        """
103
-        self.cleanup()
104
-        self.api_server.deployment_flavor = ''
105
-        self.start_servers()  # Not passing in cache_manage in pipeline...
106
-
107
-        api_port = self.api_port
108
-
109
-        # Verify decent error message returned
110
-        exe_cmd = '%s -m glance.cmd.cache_manage' % sys.executable
111
-        cmd = "%s --port=%d list-cached" % (exe_cmd, api_port)
112
-
113
-        exitcode, out, err = execute(cmd, raise_error=False)
114
-
115
-        self.assertEqual(1, exitcode)
116
-        self.assertIn(b'Cache management middleware not enabled on host',
117
-                      out.strip())
118
-
119
-        self.stop_servers()
120
-
121
-    def test_cache_index(self):
122
-        """
123
-        Test that cache index command works
124
-        """
125
-        self.cleanup()
126
-        self.start_servers(**self.__dict__.copy())
127
-
128
-        api_port = self.api_port
129
-
130
-        # Verify no cached images
131
-        exe_cmd = '%s -m glance.cmd.cache_manage' % sys.executable
132
-        cmd = "%s --port=%d list-cached" % (exe_cmd, api_port)
133
-
134
-        exitcode, out, err = execute(cmd)
135
-
136
-        self.assertEqual(0, exitcode)
137
-        self.assertIn(b'No cached images', out.strip())
138
-
139
-        ids = {}
140
-
141
-        # Add a few images and cache the second one of them
142
-        # by GETing the image...
143
-        for x in range(4):
144
-            ids[x] = self.add_image("Image%s" % x)
145
-
146
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", api_port,
147
-                                              ids[1])
148
-        http = httplib2.Http()
149
-        response, content = http.request(path, 'GET')
150
-        self.assertEqual(http_client.OK, response.status)
151
-
152
-        self.assertTrue(self.is_image_cached(ids[1]),
153
-                        "%s is not cached." % ids[1])
154
-
155
-        self.assertTrue(self.iso_date(ids[1]))
156
-
157
-        self.stop_servers()
158
-
159
-    def test_queue(self):
160
-        """
161
-        Test that we can queue and fetch images using the
162
-        CLI utility
163
-        """
164
-        self.cleanup()
165
-        self.start_servers(**self.__dict__.copy())
166
-
167
-        api_port = self.api_port
168
-
169
-        # Verify no cached images
170
-        exe_cmd = '%s -m glance.cmd.cache_manage' % sys.executable
171
-        cmd = "%s --port=%d list-cached" % (exe_cmd, api_port)
172
-
173
-        exitcode, out, err = execute(cmd)
174
-
175
-        self.assertEqual(0, exitcode)
176
-        self.assertIn(b'No cached images', out.strip())
177
-
178
-        # Verify no queued images
179
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
180
-
181
-        exitcode, out, err = execute(cmd)
182
-
183
-        self.assertEqual(0, exitcode)
184
-        self.assertIn(b'No queued images', out.strip())
185
-
186
-        ids = {}
187
-
188
-        # Add a few images and cache the second one of them
189
-        # by GETing the image...
190
-        for x in range(4):
191
-            ids[x] = self.add_image("Image%s" % x)
192
-
193
-        # Queue second image and then cache it
194
-        cmd = "%s --port=%d --force queue-image %s" % (
195
-            exe_cmd, api_port, ids[1])
196
-
197
-        exitcode, out, err = execute(cmd)
198
-
199
-        self.assertEqual(0, exitcode)
200
-
201
-        # Verify queued second image
202
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
203
-
204
-        exitcode, out, err = execute(cmd)
205
-
206
-        self.assertEqual(0, exitcode)
207
-        out = out.decode('utf-8')
208
-        self.assertIn(ids[1], out, 'Image %s was not queued!' % ids[1])
209
-
210
-        # Cache images in the queue by running the prefetcher
211
-        cache_config_filepath = os.path.join(self.test_dir, 'etc',
212
-                                             'glance-cache.conf')
213
-        cache_file_options = {
214
-            'image_cache_dir': self.api_server.image_cache_dir,
215
-            'image_cache_driver': self.image_cache_driver,
216
-            'registry_port': self.registry_server.bind_port,
217
-            'lock_path': self.test_dir,
218
-            'log_file': os.path.join(self.test_dir, 'cache.log'),
219
-            'metadata_encryption_key': "012345678901234567890123456789ab",
220
-            'filesystem_store_datadir': self.test_dir
221
-        }
222
-        with open(cache_config_filepath, 'w') as cache_file:
223
-            cache_file.write("""[DEFAULT]
224
-debug = True
225
-lock_path = %(lock_path)s
226
-image_cache_dir = %(image_cache_dir)s
227
-image_cache_driver = %(image_cache_driver)s
228
-registry_host = 127.0.0.1
229
-registry_port = %(registry_port)s
230
-metadata_encryption_key = %(metadata_encryption_key)s
231
-log_file = %(log_file)s
232
-
233
-[glance_store]
234
-filesystem_store_datadir=%(filesystem_store_datadir)s
235
-""" % cache_file_options)
236
-
237
-        cmd = ("%s -m glance.cmd.cache_prefetcher --config-file %s" %
238
-               (sys.executable, cache_config_filepath))
239
-
240
-        exitcode, out, err = execute(cmd)
241
-
242
-        self.assertEqual(0, exitcode)
243
-        self.assertEqual(b'', out.strip(), out)
244
-
245
-        # Verify no queued images
246
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
247
-
248
-        exitcode, out, err = execute(cmd)
249
-
250
-        self.assertEqual(0, exitcode)
251
-        self.assertIn(b'No queued images', out.strip())
252
-
253
-        # Verify second image now cached
254
-        cmd = "%s --port=%d list-cached" % (exe_cmd, api_port)
255
-
256
-        exitcode, out, err = execute(cmd)
257
-
258
-        self.assertEqual(0, exitcode)
259
-        out = out.decode('utf-8')
260
-        self.assertIn(ids[1], out, 'Image %s was not cached!' % ids[1])
261
-
262
-        # Queue third image and then delete it from queue
263
-        cmd = "%s --port=%d --force queue-image %s" % (
264
-            exe_cmd, api_port, ids[2])
265
-
266
-        exitcode, out, err = execute(cmd)
267
-
268
-        self.assertEqual(0, exitcode)
269
-
270
-        # Verify queued third image
271
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
272
-
273
-        exitcode, out, err = execute(cmd)
274
-
275
-        self.assertEqual(0, exitcode)
276
-        out = out.decode('utf-8')
277
-        self.assertIn(ids[2], out, 'Image %s was not queued!' % ids[2])
278
-
279
-        # Delete the image from the queue
280
-        cmd = ("%s --port=%d --force "
281
-               "delete-queued-image %s") % (exe_cmd, api_port, ids[2])
282
-
283
-        exitcode, out, err = execute(cmd)
284
-
285
-        self.assertEqual(0, exitcode)
286
-
287
-        # Verify no queued images
288
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
289
-
290
-        exitcode, out, err = execute(cmd)
291
-
292
-        self.assertEqual(0, exitcode)
293
-        self.assertIn(b'No queued images', out.strip())
294
-
295
-        # Queue all images
296
-        for x in range(4):
297
-            cmd = ("%s --port=%d --force "
298
-                   "queue-image %s") % (exe_cmd, api_port, ids[x])
299
-
300
-            exitcode, out, err = execute(cmd)
301
-
302
-            self.assertEqual(0, exitcode)
303
-
304
-        # Verify queued third image
305
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
306
-
307
-        exitcode, out, err = execute(cmd)
308
-
309
-        self.assertEqual(0, exitcode)
310
-        self.assertIn(b'Found 3 queued images', out)
311
-
312
-        # Delete the image from the queue
313
-        cmd = ("%s --port=%d --force "
314
-               "delete-all-queued-images") % (exe_cmd, api_port)
315
-
316
-        exitcode, out, err = execute(cmd)
317
-
318
-        self.assertEqual(0, exitcode)
319
-
320
-        # Verify nothing in queue anymore
321
-        cmd = "%s --port=%d list-queued" % (exe_cmd, api_port)
322
-
323
-        exitcode, out, err = execute(cmd)
324
-
325
-        self.assertEqual(0, exitcode)
326
-        self.assertIn(b'No queued images', out.strip())
327
-
328
-        # verify two image id when queue-image
329
-        cmd = ("%s --port=%d --force "
330
-               "queue-image %s %s") % (exe_cmd, api_port, ids[0], ids[1])
331
-
332
-        exitcode, out, err = execute(cmd, raise_error=False)
333
-
334
-        self.assertEqual(1, exitcode)
335
-        self.assertIn(b'Please specify one and only ID of '
336
-                      b'the image you wish to ', out.strip())
337
-
338
-        # verify two image id when delete-queued-image
339
-        cmd = ("%s --port=%d --force delete-queued-image "
340
-               "%s %s") % (exe_cmd, api_port, ids[0], ids[1])
341
-
342
-        exitcode, out, err = execute(cmd, raise_error=False)
343
-
344
-        self.assertEqual(1, exitcode)
345
-        self.assertIn(b'Please specify one and only ID of '
346
-                      b'the image you wish to ', out.strip())
347
-
348
-        # verify two image id when delete-cached-image
349
-        cmd = ("%s --port=%d --force delete-cached-image "
350
-               "%s %s") % (exe_cmd, api_port, ids[0], ids[1])
351
-
352
-        exitcode, out, err = execute(cmd, raise_error=False)
353
-
354
-        self.assertEqual(1, exitcode)
355
-        self.assertIn(b'Please specify one and only ID of '
356
-                      b'the image you wish to ', out.strip())
357
-
358
-        self.stop_servers()

+ 0
- 746
glance/tests/functional/test_cache_middleware.py View File

@@ -20,25 +20,16 @@ but that is really not relevant, as the image cache is transparent
20 20
 to the backend store.
21 21
 """
22 22
 
23
-import hashlib
24 23
 import os
25 24
 import shutil
26
-import sys
27
-import time
28 25
 import uuid
29 26
 
30 27
 import httplib2
31 28
 from oslo_serialization import jsonutils
32 29
 from oslo_utils import units
33 30
 from six.moves import http_client
34
-# NOTE(jokke): simplified transition to py3, behaves like py2 xrange
35
-from six.moves import range
36 31
 
37 32
 from glance.tests import functional
38
-from glance.tests.functional.store_utils import get_http_uri
39
-from glance.tests.functional.store_utils import setup_http
40
-from glance.tests.utils import execute
41
-from glance.tests.utils import minimal_headers
42 33
 from glance.tests.utils import skip_if_disabled
43 34
 from glance.tests.utils import xattr_writes_supported
44 35
 
@@ -47,78 +38,6 @@ FIVE_KB = 5 * units.Ki
47 38
 
48 39
 class BaseCacheMiddlewareTest(object):
49 40
 
50
-    @skip_if_disabled
51
-    def test_cache_middleware_transparent_v1(self):
52
-        """
53
-        We test that putting the cache middleware into the
54
-        application pipeline gives us transparent image caching
55
-        """
56
-        self.cleanup()
57
-        self.start_servers(**self.__dict__.copy())
58
-
59
-        # Add an image and verify a 200 OK is returned
60
-        image_data = b"*" * FIVE_KB
61
-        headers = minimal_headers('Image1')
62
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
63
-        http = httplib2.Http()
64
-        response, content = http.request(path, 'POST', headers=headers,
65
-                                         body=image_data)
66
-        self.assertEqual(http_client.CREATED, response.status)
67
-        data = jsonutils.loads(content)
68
-        self.assertEqual(hashlib.md5(image_data).hexdigest(),
69
-                         data['image']['checksum'])
70
-        self.assertEqual(FIVE_KB, data['image']['size'])
71
-        self.assertEqual("Image1", data['image']['name'])
72
-        self.assertTrue(data['image']['is_public'])
73
-
74
-        image_id = data['image']['id']
75
-
76
-        # Verify image not in cache
77
-        image_cached_path = os.path.join(self.api_server.image_cache_dir,
78
-                                         image_id)
79
-        self.assertFalse(os.path.exists(image_cached_path))
80
-
81
-        # Grab the image
82
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
83
-                                              image_id)
84
-        http = httplib2.Http()
85
-        response, content = http.request(path, 'GET')
86
-        self.assertEqual(http_client.OK, response.status)
87
-
88
-        # Verify image now in cache
89
-        image_cached_path = os.path.join(self.api_server.image_cache_dir,
90
-                                         image_id)
91
-
92
-        # You might wonder why the heck this is here... well, it's here
93
-        # because it took me forever to figure out that the disk write
94
-        # cache in Linux was causing random failures of the os.path.exists
95
-        # assert directly below this. Basically, since the cache is writing
96
-        # the image file to disk in a different process, the write buffers
97
-        # don't flush the cache file during an os.rename() properly, resulting
98
-        # in a false negative on the file existence check below. This little
99
-        # loop pauses the execution of this process for no more than 1.5
100
-        # seconds. If after that time the cached image file still doesn't
101
-        # appear on disk, something really is wrong, and the assert should
102
-        # trigger...
103
-        i = 0
104
-        while not os.path.exists(image_cached_path) and i < 30:
105
-            time.sleep(0.05)
106
-            i = i + 1
107
-
108
-        self.assertTrue(os.path.exists(image_cached_path))
109
-
110
-        # Now, we delete the image from the server and verify that
111
-        # the image cache no longer contains the deleted image
112
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
113
-                                              image_id)
114
-        http = httplib2.Http()
115
-        response, content = http.request(path, 'DELETE')
116
-        self.assertEqual(http_client.OK, response.status)
117
-
118
-        self.assertFalse(os.path.exists(image_cached_path))
119
-
120
-        self.stop_servers()
121
-
122 41
     @skip_if_disabled
123 42
     def test_cache_middleware_transparent_v2(self):
124 43
         """Ensure the v2 API image transfer calls trigger caching"""
@@ -354,102 +273,6 @@ class BaseCacheMiddlewareTest(object):
354 273
 
355 274
         self.stop_servers()
356 275
 
357
-    @skip_if_disabled
358
-    def test_cache_remote_image(self):
359
-        """
360
-        We test that caching is no longer broken for remote images
361
-        """
362
-        self.cleanup()
363
-        self.start_servers(**self.__dict__.copy())
364
-
365
-        setup_http(self)
366
-
367
-        # Add a remote image and verify a 201 Created is returned
368
-        remote_uri = get_http_uri(self, '2')
369
-        headers = {'X-Image-Meta-Name': 'Image2',
370
-                   'X-Image-Meta-disk_format': 'raw',
371
-                   'X-Image-Meta-container_format': 'ovf',
372
-                   'X-Image-Meta-Is-Public': 'True',
373
-                   'X-Image-Meta-Location': remote_uri}
374
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
375
-        http = httplib2.Http()
376
-        response, content = http.request(path, 'POST', headers=headers)
377
-        self.assertEqual(http_client.CREATED, response.status)
378
-        data = jsonutils.loads(content)
379
-        self.assertEqual(FIVE_KB, data['image']['size'])
380
-
381
-        image_id = data['image']['id']
382
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
383
-                                              image_id)
384
-
385
-        # Grab the image
386
-        http = httplib2.Http()
387
-        response, content = http.request(path, 'GET')
388
-        self.assertEqual(http_client.OK, response.status)
389
-
390
-        # Grab the image again to ensure it can be served out from
391
-        # cache with the correct size
392
-        http = httplib2.Http()
393
-        response, content = http.request(path, 'GET')
394
-        self.assertEqual(http_client.OK, response.status)
395
-        self.assertEqual(FIVE_KB, int(response['content-length']))
396
-
397
-        self.stop_servers()
398
-
399
-    @skip_if_disabled
400
-    def test_cache_middleware_trans_v1_without_download_image_policy(self):
401
-        """
402
-        Ensure the image v1 API image transfer applied 'download_image'
403
-        policy enforcement.
404
-        """
405
-        self.cleanup()
406
-        self.start_servers(**self.__dict__.copy())
407
-
408
-        # Add an image and verify a 200 OK is returned
409
-        image_data = b"*" * FIVE_KB
410
-        headers = minimal_headers('Image1')
411
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
412
-        http = httplib2.Http()
413
-        response, content = http.request(path, 'POST', headers=headers,
414
-                                         body=image_data)
415
-        self.assertEqual(http_client.CREATED, response.status)
416
-        data = jsonutils.loads(content)
417
-        self.assertEqual(hashlib.md5(image_data).hexdigest(),
418
-                         data['image']['checksum'])
419
-        self.assertEqual(FIVE_KB, data['image']['size'])
420
-        self.assertEqual("Image1", data['image']['name'])
421
-        self.assertTrue(data['image']['is_public'])
422
-
423
-        image_id = data['image']['id']
424
-
425
-        # Verify image not in cache
426
-        image_cached_path = os.path.join(self.api_server.image_cache_dir,
427
-                                         image_id)
428
-        self.assertFalse(os.path.exists(image_cached_path))
429
-
430
-        rules = {"context_is_admin": "role:admin", "default": "",
431
-                 "download_image": "!"}
432
-        self.set_policy_rules(rules)
433
-
434
-        # Grab the image
435
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
436
-                                              image_id)
437
-        http = httplib2.Http()
438
-        response, content = http.request(path, 'GET')
439
-        self.assertEqual(http_client.FORBIDDEN, response.status)
440
-
441
-        # Now, we delete the image from the server and verify that
442
-        # the image cache no longer contains the deleted image
443
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
444
-                                              image_id)
445
-        http = httplib2.Http()
446
-        response, content = http.request(path, 'DELETE')
447
-        self.assertEqual(http_client.OK, response.status)
448
-
449
-        self.assertFalse(os.path.exists(image_cached_path))
450
-
451
-        self.stop_servers()
452
-
453 276
     @skip_if_disabled
454 277
     def test_cache_middleware_trans_v2_without_download_image_policy(self):
455 278
         """
@@ -511,489 +334,6 @@ class BaseCacheMiddlewareTest(object):
511 334
 
512 335
         self.stop_servers()
513 336
 
514
-    @skip_if_disabled
515
-    def test_cache_middleware_trans_with_deactivated_image(self):
516
-        """
517
-        Ensure the image v1/v2 API image transfer forbids downloading
518
-        deactivated images.
519
-        Image deactivation is not available in v1. So, we'll deactivate the
520
-        image using v2 but test image transfer with both v1 and v2.
521
-        """
522
-        self.cleanup()
523
-        self.start_servers(**self.__dict__.copy())
524
-
525
-        # Add an image and verify a 200 OK is returned
526
-        image_data = b"*" * FIVE_KB
527
-        headers = minimal_headers('Image1')
528
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
529
-        http = httplib2.Http()
530
-        response, content = http.request(path, 'POST', headers=headers,
531
-                                         body=image_data)
532
-        self.assertEqual(http_client.CREATED, response.status)
533
-        data = jsonutils.loads(content)
534
-        self.assertEqual(hashlib.md5(image_data).hexdigest(),
535
-                         data['image']['checksum'])
536
-        self.assertEqual(FIVE_KB, data['image']['size'])
537
-        self.assertEqual("Image1", data['image']['name'])
538
-        self.assertTrue(data['image']['is_public'])
539
-
540
-        image_id = data['image']['id']
541
-
542
-        # Grab the image
543
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
544
-                                              image_id)
545
-        http = httplib2.Http()
546
-        response, content = http.request(path, 'GET')
547
-        self.assertEqual(http_client.OK, response.status)
548
-
549
-        # Verify image in cache
550
-        image_cached_path = os.path.join(self.api_server.image_cache_dir,
551
-                                         image_id)
552
-        self.assertTrue(os.path.exists(image_cached_path))
553
-
554
-        # Deactivate the image using v2
555
-        path = "http://%s:%d/v2/images/%s/actions/deactivate"
556
-        path = path % ("127.0.0.1", self.api_port, image_id)
557
-        http = httplib2.Http()
558
-        response, content = http.request(path, 'POST')
559
-        self.assertEqual(http_client.NO_CONTENT, response.status)
560
-
561
-        # Download the image with v1. Ensure it is forbidden
562
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
563
-                                              image_id)
564
-        http = httplib2.Http()
565
-        response, content = http.request(path, 'GET')
566
-        self.assertEqual(http_client.FORBIDDEN, response.status)
567
-
568
-        # Download the image with v2. This succeeds because
569
-        # we are in admin context.
570
-        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
571
-                                                   image_id)
572
-        http = httplib2.Http()
573
-        response, content = http.request(path, 'GET')
574
-        self.assertEqual(http_client.OK, response.status)
575
-
576
-        # Reactivate the image using v2
577
-        path = "http://%s:%d/v2/images/%s/actions/reactivate"
578
-        path = path % ("127.0.0.1", self.api_port, image_id)
579
-        http = httplib2.Http()
580
-        response, content = http.request(path, 'POST')
581
-        self.assertEqual(http_client.NO_CONTENT, response.status)
582
-
583
-        # Download the image with v1. Ensure it is allowed
584
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
585
-                                              image_id)
586
-        http = httplib2.Http()
587
-        response, content = http.request(path, 'GET')
588
-        self.assertEqual(http_client.OK, response.status)
589
-
590
-        # Download the image with v2. Ensure it is allowed
591
-        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
592
-                                                   image_id)
593
-        http = httplib2.Http()
594
-        response, content = http.request(path, 'GET')
595
-        self.assertEqual(http_client.OK, response.status)
596
-
597
-        # Now, we delete the image from the server and verify that
598
-        # the image cache no longer contains the deleted image
599
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
600
-                                              image_id)
601
-        http = httplib2.Http()
602
-        response, content = http.request(path, 'DELETE')
603
-        self.assertEqual(http_client.OK, response.status)
604
-
605
-        self.assertFalse(os.path.exists(image_cached_path))
606
-
607
-        self.stop_servers()
608
-
609
-
610
-class BaseCacheManageMiddlewareTest(object):
611
-
612
-    """Base test class for testing cache management middleware"""
613
-
614
-    def verify_no_images(self):
615
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
616
-        http = httplib2.Http()
617
-        response, content = http.request(path, 'GET')
618
-        self.assertEqual(http_client.OK, response.status)
619
-        data = jsonutils.loads(content)
620
-        self.assertIn('images', data)
621
-        self.assertEqual(0, len(data['images']))
622
-
623
-    def add_image(self, name):
624
-        """
625
-        Adds an image and returns the newly-added image
626
-        identifier
627
-        """
628
-        image_data = b"*" * FIVE_KB
629
-        headers = minimal_headers('%s' % name)
630
-
631
-        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
632
-        http = httplib2.Http()
633
-        response, content = http.request(path, 'POST', headers=headers,
634
-                                         body=image_data)
635
-        self.assertEqual(http_client.CREATED, response.status)
636
-        data = jsonutils.loads(content)
637
-        self.assertEqual(hashlib.md5(image_data).hexdigest(),
638
-                         data['image']['checksum'])
639
-        self.assertEqual(FIVE_KB, data['image']['size'])
640
-        self.assertEqual(name, data['image']['name'])
641
-        self.assertTrue(data['image']['is_public'])
642
-        return data['image']['id']
643
-
644
-    def verify_no_cached_images(self):
645
-        """
646
-        Verify no images in the image cache
647
-        """
648
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
649
-        http = httplib2.Http()
650
-        response, content = http.request(path, 'GET')
651
-        self.assertEqual(http_client.OK, response.status)
652
-
653
-        data = jsonutils.loads(content)
654
-        self.assertIn('cached_images', data)
655
-        self.assertEqual([], data['cached_images'])
656
-
657
-    @skip_if_disabled
658
-    def test_user_not_authorized(self):
659
-        self.cleanup()
660
-        self.start_servers(**self.__dict__.copy())
661
-        self.verify_no_images()
662
-
663
-        image_id1 = self.add_image("Image1")
664
-        image_id2 = self.add_image("Image2")
665
-
666
-        # Verify image does not yet show up in cache (we haven't "hit"
667
-        # it yet using a GET /images/1 ...
668
-        self.verify_no_cached_images()
669
-
670
-        # Grab the image
671
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
672
-                                              image_id1)
673
-        http = httplib2.Http()
674
-        response, content = http.request(path, 'GET')
675
-        self.assertEqual(http_client.OK, response.status)
676
-
677
-        # Verify image now in cache
678
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
679
-        http = httplib2.Http()
680
-        response, content = http.request(path, 'GET')
681
-        self.assertEqual(http_client.OK, response.status)
682
-
683
-        data = jsonutils.loads(content)
684
-        self.assertIn('cached_images', data)
685
-
686
-        cached_images = data['cached_images']
687
-        self.assertEqual(1, len(cached_images))
688
-        self.assertEqual(image_id1, cached_images[0]['image_id'])
689
-
690
-        # Set policy to disallow access to cache management
691
-        rules = {"manage_image_cache": '!'}
692
-        self.set_policy_rules(rules)
693
-
694
-        # Verify an unprivileged user cannot see cached images
695
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
696
-        http = httplib2.Http()
697
-        response, content = http.request(path, 'GET')
698
-        self.assertEqual(http_client.FORBIDDEN, response.status)
699
-
700
-        # Verify an unprivileged user cannot delete images from the cache
701
-        path = "http://%s:%d/v1/cached_images/%s" % ("127.0.0.1",
702
-                                                     self.api_port, image_id1)
703
-        http = httplib2.Http()
704
-        response, content = http.request(path, 'DELETE')
705
-        self.assertEqual(http_client.FORBIDDEN, response.status)
706
-
707
-        # Verify an unprivileged user cannot delete all cached images
708
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
709
-        http = httplib2.Http()
710
-        response, content = http.request(path, 'DELETE')
711
-        self.assertEqual(http_client.FORBIDDEN, response.status)
712
-
713
-        # Verify an unprivileged user cannot queue an image
714
-        path = "http://%s:%d/v1/queued_images/%s" % ("127.0.0.1",
715
-                                                     self.api_port, image_id2)
716
-        http = httplib2.Http()
717
-        response, content = http.request(path, 'PUT')
718
-        self.assertEqual(http_client.FORBIDDEN, response.status)
719
-
720
-        self.stop_servers()
721
-
722
-    @skip_if_disabled
723
-    def test_cache_manage_get_cached_images(self):
724
-        """
725
-        Tests that cached images are queryable
726
-        """
727
-        self.cleanup()
728
-        self.start_servers(**self.__dict__.copy())
729
-
730
-        self.verify_no_images()
731
-
732
-        image_id = self.add_image("Image1")
733
-
734
-        # Verify image does not yet show up in cache (we haven't "hit"
735
-        # it yet using a GET /images/1 ...
736
-        self.verify_no_cached_images()
737
-
738
-        # Grab the image
739
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
740
-                                              image_id)
741
-        http = httplib2.Http()
742
-        response, content = http.request(path, 'GET')
743
-        self.assertEqual(http_client.OK, response.status)
744
-
745
-        # Verify image now in cache
746
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
747
-        http = httplib2.Http()
748
-        response, content = http.request(path, 'GET')
749
-        self.assertEqual(http_client.OK, response.status)
750
-
751
-        data = jsonutils.loads(content)
752
-        self.assertIn('cached_images', data)
753
-
754
-        # Verify the last_modified/last_accessed values are valid floats
755
-        for cached_image in data['cached_images']:
756
-            for time_key in ('last_modified', 'last_accessed'):
757
-                time_val = cached_image[time_key]
758
-                try:
759
-                    float(time_val)
760
-                except ValueError:
761
-                    self.fail('%s time %s for cached image %s not a valid '
762
-                              'float' % (time_key, time_val,
763
-                                         cached_image['image_id']))
764
-
765
-        cached_images = data['cached_images']
766
-        self.assertEqual(1, len(cached_images))
767
-        self.assertEqual(image_id, cached_images[0]['image_id'])
768
-        self.assertEqual(0, cached_images[0]['hits'])
769
-
770
-        # Hit the image
771
-        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
772
-                                              image_id)
773
-        http = httplib2.Http()
774
-        response, content = http.request(path, 'GET')
775
-        self.assertEqual(http_client.OK, response.status)
776
-
777
-        # Verify image hits increased in output of manage GET
778
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
779
-        http = httplib2.Http()
780
-        response, content = http.request(path, 'GET')
781
-        self.assertEqual(http_client.OK, response.status)
782
-
783
-        data = jsonutils.loads(content)
784
-        self.assertIn('cached_images', data)
785
-
786
-        cached_images = data['cached_images']
787
-        self.assertEqual(1, len(cached_images))
788
-        self.assertEqual(image_id, cached_images[0]['image_id'])
789
-        self.assertEqual(1, cached_images[0]['hits'])
790
-
791
-        self.stop_servers()
792
-
793
-    @skip_if_disabled
794
-    def test_cache_manage_delete_cached_images(self):
795
-        """
796
-        Tests that cached images may be deleted
797
-        """
798
-        self.cleanup()
799
-        self.start_servers(**self.__dict__.copy())
800
-
801
-        self.verify_no_images()
802
-
803
-        ids = {}
804
-
805
-        # Add a bunch of images...
806
-        for x in range(4):
807
-            ids[x] = self.add_image("Image%s" % str(x))
808
-
809
-        # Verify no images in cached_images because no image has been hit
810
-        # yet using a GET /images/<IMAGE_ID> ...
811
-        self.verify_no_cached_images()
812
-
813
-        # Grab the images, essentially caching them...
814
-        for x in range(4):
815
-            path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
816
-                                                  ids[x])
817
-            http = httplib2.Http()
818
-            response, content = http.request(path, 'GET')
819
-            self.assertEqual(http_client.OK, response.status,
820
-                             "Failed to find image %s" % ids[x])
821
-
822
-        # Verify images now in cache
823
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
824
-        http = httplib2.Http()
825
-        response, content = http.request(path, 'GET')
826
-        self.assertEqual(http_client.OK, response.status)
827
-
828
-        data = jsonutils.loads(content)
829
-        self.assertIn('cached_images', data)
830
-
831
-        cached_images = data['cached_images']
832
-        self.assertEqual(4, len(cached_images))
833
-
834
-        for x in range(4, 0):  # Cached images returned last modified order
835
-            self.assertEqual(ids[x], cached_images[x]['image_id'])
836
-            self.assertEqual(0, cached_images[x]['hits'])
837
-
838
-        # Delete third image of the cached images and verify no longer in cache
839
-        path = "http://%s:%d/v1/cached_images/%s" % ("127.0.0.1",
840
-                                                     self.api_port, ids[2])
841
-        http = httplib2.Http()
842
-        response, content = http.request(path, 'DELETE')
843
-        self.assertEqual(http_client.OK, response.status)
844
-
845
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
846
-        http = httplib2.Http()
847
-        response, content = http.request(path, 'GET')
848
-        self.assertEqual(http_client.OK, response.status)
849
-
850
-        data = jsonutils.loads(content)
851
-        self.assertIn('cached_images', data)
852
-
853
-        cached_images = data['cached_images']
854
-        self.assertEqual(3, len(cached_images))
855
-        self.assertNotIn(ids[2], [x['image_id'] for x in cached_images])
856
-
857
-        # Delete all cached images and verify nothing in cache
858
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
859
-        http = httplib2.Http()
860
-        response, content = http.request(path, 'DELETE')
861
-        self.assertEqual(http_client.OK, response.status)
862
-
863
-        path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port)
864
-        http = httplib2.Http()
865
-        response, content = http.request(path, 'GET')
866
-        self.assertEqual(http_client.OK, response.status)
867
-
868
-        data = jsonutils.loads(content)
869
-        self.assertIn('cached_images', data)
870
-
871
-        cached_images = data['cached_images']
872
-        self.assertEqual(0, len(cached_images))
873
-
874
-        self.stop_servers()
875
-
876
-    @skip_if_disabled
877
-    def test_cache_manage_delete_queued_images(self):
878
-        """
879
-        Tests that all queued images may be deleted at once
880
-        """
881
-        self.cleanup()
882
-        self.start_servers(**self.__dict__.copy())
883
-
884
-        self.verify_no_images()
885
-
886
-        ids = {}
887
-        NUM_IMAGES = 4
888
-
889
-        # Add and then queue some images
890
-        for x in range(NUM_IMAGES):
891
-            ids[x] = self.add_image("Image%s" % str(x))
892
-            path = "http://%s:%d/v1/queued_images/%s" % ("127.0.0.1",
893
-                                                         self.api_port, ids[x])
894
-            http = httplib2.Http()
895
-            response, content = http.request(path, 'PUT')
896
-            self.assertEqual(http_client.OK, response.status)
897
-
898
-        # Delete all queued images
899
-        path = "http://%s:%d/v1/queued_images" % ("127.0.0.1", self.api_port)
900
-        http = httplib2.Http()
901
-        response, content = http.request(path, 'DELETE')
902
-        self.assertEqual(http_client.OK, response.status)
903
-
904
-        data = jsonutils.loads(content)
905
-        num_deleted = data['num_deleted']
906
-        self.assertEqual(NUM_IMAGES, num_deleted)
907
-
908
-        # Verify a second delete now returns num_deleted=0
909
-        path = "http://%s:%d/v1/queued_images" % ("127.0.0.1", self.api_port)
910
-        http = httplib2.Http()
911
-        response, content = http.request(path, 'DELETE')
912
-        self.assertEqual(http_client.OK, response.status)
913
-
914
-        data = jsonutils.loads(content)
915
-        num_deleted = data['num_deleted']
916
-        self.assertEqual(0, num_deleted)
917
-
918
-        self.stop_servers()
919
-
920
-    @skip_if_disabled
921
-    def test_queue_and_prefetch(self):
922
-        """
923
-        Tests that images may be queued and prefetched
924
-        """
925
-        self.cleanup()
926
-        self.start_servers(**self.__dict__.copy())
927
-
928
-        cache_config_filepath = os.path.join(self.test_dir, 'etc',
929
-                                             'glance-cache.conf')
930
-        cache_file_options = {
931
-            'image_cache_dir': self.api_server.image_cache_dir,
932
-            'image_cache_driver': self.image_cache_driver,
933
-            'registry_port': self.registry_server.bind_port,
934
-            'log_file': os.path.join(self.test_dir, 'cache.log'),
935
-            'lock_path': self.test_dir,
936
-            'metadata_encryption_key': "012345678901234567890123456789ab",
937
-            'filesystem_store_datadir': self.test_dir
938
-        }
939
-        with open(cache_config_filepath, 'w') as cache_file:
940
-            cache_file.write("""[DEFAULT]
941
-debug = True
942
-lock_path = %(lock_path)s
943
-image_cache_dir = %(image_cache_dir)s
944
-image_cache_driver = %(image_cache_driver)s
945
-registry_host = 127.0.0.1
946
-registry_port = %(registry_port)s
947
-metadata_encryption_key = %(metadata_encryption_key)s
948
-log_file = %(log_file)s
949
-
950
-[glance_store]
951
-filesystem_store_datadir=%(filesystem_store_datadir)s
952
-""" % cache_file_options)
953
-
954
-        self.verify_no_images()
955
-
956
-        ids = {}
957
-
958
-        # Add a bunch of images...
959
-        for x in range(4):
960
-            ids[x] = self.add_image("Image%s" % str(x))
961
-
962
-        # Queue the first image, verify no images still in cache after queueing
963
-        # then run the prefetcher and verify that the image is then in the
964
-        # cache
965
-        path = "http://%s:%d/v1/queued_images/%s" % ("127.0.0.1",
966
-                                                     self.api_port, ids[0])
967
-        http = httplib2.Http()
968
-        response, content = http.request(path, 'PUT')
969
-        self.assertEqual(http_client.OK, response.status)
970
-
971
-        self.verify_no_cached_images()
972
-
973
-        cmd = ("%s -m glance.cmd.cache_prefetcher --config-file %s" %
974
-