def test_task_schema_api(self): # 0. GET /schemas/task # Verify schema for task path = "/v2/schemas/task" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) schema = tasks.get_task_schema() expected_schema = schema.minimal() data = json.loads(content) self.assertIsNotNone(data) self.assertEqual(expected_schema, data) # 1. GET /schemas/tasks # Verify schema for tasks path = "/v2/schemas/tasks" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) schema = tasks.get_collection_schema() expected_schema = schema.minimal() data = json.loads(content) self.assertIsNotNone(data) self.assertEqual(expected_schema, data)
def test_task_schema_api(self): # 0. GET /schemas/task # Verify schema for task path = "/v2/schemas/task" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) schema = tasks.get_task_schema() expected_schema = schema.minimal() data = json.loads(content) self.assertIsNotNone(data) self.assertEqual(expected_schema, data) # 1. GET /schemas/tasks # Verify schema for tasks path = "/v2/schemas/tasks" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) schema = tasks.get_collection_schema() expected_schema = schema.minimal() data = json.loads(content) self.assertIsNotNone(data) self.assertEqual(expected_schema, data) # NOTE(nikhil): wait for all task executions to finish before exiting # else there is a risk of running into deadlock self._wait_on_task_execution()
def test_create_ensure_expires_at_is_not_returned(self): response = webob.Response() self.serializer.create(response, self.fixtures[0]) serialized_task = jsonutils.loads(response.body) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[0]['task'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[0]['task_details'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[0]['task_details'].input, serialized_task['input']) self.assertFalse('expires_at' in serialized_task) self.assertEqual('application/json', response.content_type) response = webob.Response() self.serializer.create(response, self.fixtures[1]) serialized_task = jsonutils.loads(response.body) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[1]['task'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[1]['task_details'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[1]['task_details'].input, serialized_task['input']) self.assertFalse('expires_at' in serialized_task) self.assertEqual('application/json', response.content_type)
def test_all_task_api(self): # 0. GET /tasks # Verify no tasks path = "/v2/tasks" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) content_dict = json.loads(content) self.assertEqual(response.status, 200) self.assertFalse(content_dict['tasks']) # 1. GET /tasks/{task_id} # Verify non-existent task task_id = 'NON_EXISTENT_TASK' path = "/v2/tasks/%s" % task_id response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 404) # 2. POST /tasks # Create a new task task_owner = 'tenant1' data, req_input = self._post_new_task(owner=task_owner) # 3. GET /tasks/{task_id} # Get an existing task task_id = data['id'] path = "/v2/tasks/%s" % task_id response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) # 4. GET /tasks # Get all tasks (not deleted) path = "/v2/tasks" response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) self.assertIsNotNone(content) data = json.loads(content) self.assertIsNotNone(data) self.assertEqual(1, len(data['tasks'])) #NOTE(venkatesh) find a way to get expected_keys from tasks controller expected_keys = set(['id', 'type', 'owner', 'status', 'created_at', 'updated_at', 'self', 'schema']) task = data['tasks'][0] self.assertEqual(expected_keys, set(task.keys())) self.assertEqual(req_input['type'], task['type']) self.assertEqual(task_owner, task['owner']) self.assertEqual('processing', task['status']) self.assertIsNotNone(task['created_at']) self.assertIsNotNone(task['updated_at']) # NOTE(nikhil): wait for all task executions to finish before exiting # else there is a risk of running into deadlock self._wait_on_task_execution()
def test_create(self): response = webob.Response() self.serializer.create(response, self.fixtures[3]) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[3].task_id, jsonutils.loads(response.body)['id']) self.assertTrue('expires_at' in jsonutils.loads(response.body)) self.assertEqual('application/json', response.content_type)
def test_property_ops_when_quota_violated(self): # Image list must be empty to begin with image_list = self._get()["images"] self.assertEqual(0, len(image_list)) orig_property_quota = 10 CONF.set_override("image_property_quota", orig_property_quota) # Create an image (with deployer-defined properties) req_body = {"name": "testimg", "disk_format": "aki", "container_format": "aki"} for i in range(orig_property_quota): req_body["k_%d" % i] = "v_%d" % i image = self._create_image(req_body) image_id = image["id"] for i in range(orig_property_quota): self.assertEqual("v_%d" % i, image["k_%d" % i]) # Now reduce property quota. We should be allowed to modify/delete # existing properties (even if the result still exceeds property quota) # but not add new properties nor replace existing properties with new # properties (as long as we're over the quota) self.config(image_property_quota=2) patch_body = [{"op": "replace", "path": "/k_4", "value": "v_4.new"}] image = jsonutils.loads(self._patch(image_id, patch_body, 200)) self.assertEqual("v_4.new", image["k_4"]) patch_body = [{"op": "remove", "path": "/k_7"}] image = jsonutils.loads(self._patch(image_id, patch_body, 200)) self.assertNotIn("k_7", image) patch_body = [{"op": "add", "path": "/k_100", "value": "v_100"}] self._patch(image_id, patch_body, 413) image = self._get(image_id) self.assertNotIn("k_100", image) patch_body = [{"op": "remove", "path": "/k_5"}, {"op": "add", "path": "/k_100", "value": "v_100"}] self._patch(image_id, patch_body, 413) image = self._get(image_id) self.assertNotIn("k_100", image) self.assertIn("k_5", image) # temporary violations to property quota should be allowed as long as # it's within one PATCH request and the end result does not violate # quotas. patch_body = [ {"op": "add", "path": "/k_100", "value": "v_100"}, {"op": "add", "path": "/k_99", "value": "v_99"}, ] to_rm = ["k_%d" % i for i in range(orig_property_quota) if i != 7] patch_body.extend([{"op": "remove", "path": "/%s" % k} for k in to_rm]) image = jsonutils.loads(self._patch(image_id, patch_body, 200)) self.assertEqual("v_99", image["k_99"]) self.assertEqual("v_100", image["k_100"]) for k in to_rm: self.assertNotIn(k, image)
def test_update_image(self): """Tests that the registry API updates the image""" fixture = {'name': 'fake public image #2', 'min_disk': 5, 'min_ram': 256, 'disk_format': 'raw'} req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_update', 'kwargs': {'values': fixture, 'image_id': UUID2} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) res_dict = jsonutils.loads(res.body)[0] self.assertNotEqual(res_dict['created_at'], res_dict['updated_at']) for k, v in six.iteritems(fixture): self.assertEqual(v, res_dict[k])
def _get_authenticated_context(self, req): # NOTE(bcwaldon): X-Roles is a csv string, but we need to parse # it into a list to be useful roles_header = req.headers.get("X-Roles", "") roles = [r.strip().lower() for r in roles_header.split(",")] # NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token deprecated_token = req.headers.get("X-Storage-Token") service_catalog = None if req.headers.get("X-Service-Catalog") is not None: try: catalog_header = req.headers.get("X-Service-Catalog") service_catalog = jsonutils.loads(catalog_header) except ValueError: raise webob.exc.HTTPInternalServerError(_("Invalid service catalog json.")) kwargs = { "user": req.headers.get("X-User-Id"), "tenant": req.headers.get("X-Tenant-Id"), "roles": roles, "is_admin": CONF.admin_role.strip().lower() in roles, "auth_tok": req.headers.get("X-Auth-Token", deprecated_token), "owner_is_tenant": CONF.owner_is_tenant, "service_catalog": service_catalog, "policy_enforcer": self.policy_enforcer, } return glance.context.RequestContext(**kwargs)
def _wait_on_task_execution(self): """Wait until all the tasks have finished execution and are in state of success or failure. """ start = timeutils.utcnow() # wait for maximum of 5 seconds while timeutils.delta_seconds(start, timeutils.utcnow()) < 5: wait = False # Verify that no task is in status of pending or processing path = "/v2/tasks" res, content = self.http.request(path, 'GET', headers=minimal_task_headers()) content_dict = json.loads(content) self.assertEqual(res.status, 200) res_tasks = content_dict['tasks'] if len(res_tasks) != 0: for task in res_tasks: if task['status'] in ('pending', 'processing'): wait = True break if wait: time.sleep(0.05) continue else: break
def test_get_index(self): """ Tests that the image_get_all command returns list of images """ fixture = {'id': UUID2, 'name': 'fake image #2', 'size': 19, 'checksum': None} req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'filters': fixture}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) images = jsonutils.loads(res.body)[0] self.assertEqual(len(images), 1) for k, v in six.iteritems(fixture): self.assertEqual(v, images[0][k])
def test_user_not_authorized(self): self.cleanup() self.start_servers(**self.__dict__.copy()) self.verify_no_images() image_id1 = self.add_image("Image1") image_id2 = self.add_image("Image2") # Verify image does not yet show up in cache (we haven't "hit" # it yet using a GET /images/1 ... self.verify_no_cached_images() # Grab the image path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id1) http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 200) # Verify image now in cache path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 200) data = jsonutils.loads(content) self.assertTrue("cached_images" in data) cached_images = data["cached_images"] self.assertEqual(1, len(cached_images)) self.assertEqual(image_id1, cached_images[0]["image_id"]) # Set policy to disallow access to cache management rules = {"manage_image_cache": "!"} self.set_policy_rules(rules) # Verify an unprivileged user cannot see cached images path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, "GET") self.assertEqual(response.status, 403) # Verify an unprivileged user cannot delete images from the cache path = "http://%s:%d/v1/cached_images/%s" % ("127.0.0.1", self.api_port, image_id1) http = httplib2.Http() response, content = http.request(path, "DELETE") self.assertEqual(response.status, 403) # Verify an unprivileged user cannot delete all cached images path = "http://%s:%d/v1/cached_images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, "DELETE") self.assertEqual(response.status, 403) # Verify an unprivileged user cannot queue an image path = "http://%s:%d/v1/queued_images/%s" % ("127.0.0.1", self.api_port, image_id2) http = httplib2.Http() response, content = http.request(path, "PUT") self.assertEqual(response.status, 403) self.stop_servers()
def _v2_auth(self, token_url): creds = self.creds creds = { "auth": { "tenantName": creds["tenant"], "passwordCredentials": {"username": creds["username"], "password": creds["password"]}, } } headers = {} headers["Content-Type"] = "application/json" req_body = jsonutils.dumps(creds) resp, resp_body = self._do_request(token_url, "POST", headers=headers, body=req_body) if resp.status == 200: resp_auth = jsonutils.loads(resp_body)["access"] creds_region = self.creds.get("region") if self.configure_via_auth: endpoint = get_endpoint(resp_auth["serviceCatalog"], endpoint_region=creds_region) self.management_url = endpoint self.auth_token = resp_auth["token"]["id"] elif resp.status == 305: raise exception.RedirectException(resp["location"]) elif resp.status == 400: raise exception.AuthBadRequest(url=token_url) elif resp.status == 401: raise exception.NotAuthenticated() elif resp.status == 404: raise exception.AuthUrlNotFound(url=token_url) else: raise Exception(_("Unexpected response: %s") % resp.status)
def test_get_index_marker_and_container_format_desc(self): """Test marker and null container format descending Tests that the registry API returns 200 when a marker and a null container_format are combined descending order """ UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': None, 'name': 'Fake image', 'size': 19, 'checksum': None} db_api.image_create(self.context, extra_fixture) req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'marker': UUID3, 'sort_key': 'container_format', 'sort_dir': 'desc'}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) images = jsonutils.loads(res.body)[0] self.assertEqual(len(images), 0)
def get_queued_images(self, **kwargs): """ Returns a list of images queued for caching """ res = self.do_request("GET", "/queued_images") data = json.loads(res.read())['queued_images'] return data
def get_cached_images(self, **kwargs): """ Returns a list of images stored in the image cache. """ res = self.do_request("GET", "/cached_images") data = json.loads(res.read())['cached_images'] return data
def test_create_image(self): """Tests that the registry API creates the image""" fixture = {'name': 'fake public image', 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf'} req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_create', 'kwargs': {'values': fixture} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) res_dict = jsonutils.loads(res.body)[0] for k, v in six.iteritems(fixture): self.assertEqual(v, res_dict[k]) # Test status was updated properly self.assertEqual('active', res_dict['status'])
def _json_request(self, auth_host, auth_port, method, path, body=None, additional_headers=None): """HTTP request helper used to make json requests. :param method: http method :param path: relative request url :param body: dict to encode to json as request body. Optional. :param additional_headers: dict of additional headers to send with http request. Optional. :return (http response object, response body parsed as json) :raise ServerError when unable to communicate with keystone """ kwargs = { 'headers': { 'Content-type': 'application/json', 'Accept': 'application/json', }, } if additional_headers: kwargs['headers'].update(additional_headers) if body: kwargs['body'] = jsonutils.dumps(body) path = self.auth_admin_prefix + path response, body = self._http_request(auth_host, auth_port, method, path, **kwargs) try: data = jsonutils.loads(body) except ValueError: self.LOG.debug('Keystone did not return json-encoded body') data = {} return response, data
def update_image(self, image_id, image_metadata, purge_props=False, from_state=None): """ Updates Registry's information about an image """ if 'image' not in image_metadata: image_metadata = dict(image=image_metadata) encrypted_metadata = self.encrypt_metadata(image_metadata['image']) image_metadata['image'] = encrypted_metadata image_metadata['from_state'] = from_state body = jsonutils.dumps(image_metadata) headers = { 'Content-Type': 'application/json', } if purge_props: headers["X-Glance-Registry-Purge-Props"] = "true" res = self.do_request("PUT", "/images/%s" % image_id, body=body, headers=headers) data = jsonutils.loads(res.read()) image = data['image'] return self.decrypt_metadata(image)
def test_index_next_marker(self): request = webob.Request.blank('/v2/tasks') response = webob.Response(request=request) result = {'tasks': self.fixtures, 'next_marker': UUID2} self.serializer.index(response, result) output = jsonutils.loads(response.body) self.assertEqual('/v2/tasks?marker=%s' % UUID2, output['next'])
def test_index(self): expected = { 'members': [ { 'image_id': UUID2, 'member_id': TENANT1, 'status': 'accepted', 'created_at': ISOTIME, 'updated_at': ISOTIME, 'schema': '/v2/schemas/member', }, { 'image_id': UUID2, 'member_id': TENANT2, 'status': 'pending', 'created_at': ISOTIME, 'updated_at': ISOTIME, 'schema': '/v2/schemas/member', }, ], 'schema': '/v2/schemas/members', } request = webob.Request.blank('/v2/images/%s/members' % UUID2) response = webob.Response(request=request) result = {'members': self.fixtures} self.serializer.index(response, result) actual = jsonutils.loads(response.body) self.assertEqual(expected, actual) self.assertEqual('application/json', response.content_type)
def test_to_json_with_more_deep_format(self): fixture = {"is_public": True, "name": [{"name1": "test"}]} expected = {"is_public": True, "name": [{"name1": "test"}]} actual = wsgi.JSONResponseSerializer().to_json(fixture) actual = jsonutils.loads(actual) for k in expected: self.assertEqual(expected[k], actual[k])
def test_delete_task(self): # 0. POST /tasks # Create a new task with valid input and type task_data = _new_task_fixture() task_owner = 'tenant1' body_content = json.dumps(task_data) path = "/v2/tasks" response, content = self.http.request( path, 'POST', headers=minimal_task_headers(task_owner), body=body_content) self.assertEqual(response.status, 201) data = json.loads(content) task_id = data['id'] # 1. DELETE on /tasks/{task_id} # Attempt to delete a task path = "/v2/tasks/%s" % task_id response, content = self.http.request(path, 'DELETE', headers=minimal_task_headers()) self.assertEqual(response.status, 405) self.assertEqual('GET', response.webob_resp.headers.get('Allow')) self.assertEqual(('GET',), response.webob_resp.allow) self.assertEqual(('GET',), response.allow) # 2. GET /tasks/{task_id} # Ensure that methods mentioned in the Allow header work path = "/v2/tasks/%s" % task_id response, content = self.http.request(path, 'GET', headers=minimal_task_headers()) self.assertEqual(response.status, 200) self.assertIsNotNone(content)
def test_index(self): expected = { "members": [ { "image_id": UUID2, "member_id": TENANT1, "status": "accepted", "created_at": ISOTIME, "updated_at": ISOTIME, "schema": "/v2/schemas/member", }, { "image_id": UUID2, "member_id": TENANT2, "status": "pending", "created_at": ISOTIME, "updated_at": ISOTIME, "schema": "/v2/schemas/member", }, ], "schema": "/v2/schemas/members", } request = webob.Request.blank("/v2/images/%s/members" % UUID2) response = webob.Response(request=request) result = {"members": self.fixtures} self.serializer.index(response, result) actual = jsonutils.loads(response.body) self.assertEqual(expected, actual) self.assertEqual("application/json", response.content_type)
def _get_authenticated_context(self, req): #NOTE(bcwaldon): X-Roles is a csv string, but we need to parse # it into a list to be useful roles_header = req.headers.get('X-Roles', '') roles = [r.strip().lower() for r in roles_header.split(',')] #NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token deprecated_token = req.headers.get('X-Storage-Token') service_catalog = None if req.headers.get('X-Service-Catalog') is not None: try: catalog_header = req.headers.get('X-Service-Catalog') service_catalog = jsonutils.loads(catalog_header) except ValueError: raise webob.exc.HTTPInternalServerError( _('Invalid service catalog json.')) kwargs = { 'user': req.headers.get('X-User-Id'), 'tenant': req.headers.get('X-Tenant-Id'), 'roles': roles, 'is_admin': CONF.admin_role.strip().lower() in roles, 'auth_token': req.headers.get('X-Auth-Token', deprecated_token), 'owner_is_tenant': CONF.owner_is_tenant, 'service_catalog': service_catalog, 'policy_enforcer': self.policy_enforcer, } return glance.context.RequestContext(**kwargs)
def test_get_index_sort_name_asc(self): """ Tests that the registry API returns list of public images sorted alphabetically by name in ascending order. """ UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'asdf', 'size': 19, 'checksum': None} db_api.image_create(self.context, extra_fixture) UUID4 = _gen_uuid() extra_fixture = {'id': UUID4, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'xyz', 'size': 20, 'checksum': None} db_api.image_create(self.context, extra_fixture) UUID5 = _gen_uuid() extra_fixture = {'id': UUID5, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': None, 'size': 20, 'checksum': None} db_api.image_create(self.context, extra_fixture) req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'sort_key': 'name', 'sort_dir': 'asc'} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) res_dict = jsonutils.loads(res.body)[0] images = res_dict self.assertEqual(len(images), 5) self.assertEqual(images[0]['id'], UUID5) self.assertEqual(images[1]['id'], UUID3) self.assertEqual(images[2]['id'], UUID1) self.assertEqual(images[3]['id'], UUID2) self.assertEqual(images[4]['id'], UUID4)
def test_cache_middleware_trans_v2_without_download_image_policy(self): """ Ensure the image v2 API image transfer applied 'download_image' policy enforcement. """ self.cleanup() self.start_servers(**self.__dict__.copy()) # Add an image and verify success path = "http://%s:%d/v2/images" % ("0.0.0.0", self.api_port) http = httplib2.Http() headers = {'content-type': 'application/json'} image_entity = { 'name': 'Image1', 'visibility': 'public', 'container_format': 'bare', 'disk_format': 'raw', } response, content = http.request(path, 'POST', headers=headers, body=jsonutils.dumps(image_entity)) self.assertEqual(response.status, 201) data = jsonutils.loads(content) image_id = data['id'] path = "http://%s:%d/v2/images/%s/file" % ("0.0.0.0", self.api_port, image_id) headers = {'content-type': 'application/octet-stream'} image_data = "*" * FIVE_KB response, content = http.request(path, 'PUT', headers=headers, body=image_data) self.assertEqual(response.status, 204) # Verify image not in cache image_cached_path = os.path.join(self.api_server.image_cache_dir, image_id) self.assertFalse(os.path.exists(image_cached_path)) rules = {"context_is_admin": "role:admin", "default": "", "download_image": "!"} self.set_policy_rules(rules) # Grab the image http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 403) # Now, we delete the image from the server and verify that # the image cache no longer contains the deleted image path = "http://%s:%d/v2/images/%s" % ("0.0.0.0", self.api_port, image_id) http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 204) self.assertFalse(os.path.exists(image_cached_path)) self.stop_servers()
def test_index_next_marker(self): request = webob.Request.blank("/v2/tasks") response = webob.Response(request=request) task_fixtures = [f["task"] for f in self.fixtures] result = {"tasks": task_fixtures, "next_marker": UUID2} self.serializer.index(response, result) output = jsonutils.loads(response.body) self.assertEqual("/v2/tasks?marker=%s" % UUID2, output["next"])
def verify_no_images(self): path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) data = jsonutils.loads(content) self.assertTrue('images' in data) self.assertEqual(0, len(data['images']))
def test_to_json_with_date_format_value(self): fixture = {"date": datetime.datetime(1900, 3, 8, 2)} expected = {"date": {"_value": "1900-03-08T02:00:00.000000", "_type": "datetime"}} actual = rpc.RPCJSONSerializer().to_json(fixture) actual = jsonutils.loads(actual) for k in expected['date']: self.assertEqual(expected['date'][k], actual['date'][k])
def delete_image(self, image_id): """ Deletes Registry's information about an image """ res = self.do_request("DELETE", "/images/%s" % image_id) data = jsonutils.loads(res.read()) image = data['image'] return image
def load_custom_properties(): """Find the schema properties files and load them into a dict.""" filename = 'schema-image.json' match = CONF.find_file(filename) if match: schema_file = open(match) schema_data = schema_file.read() return json.loads(schema_data) else: msg = _('Could not find schema properties file %s. Continuing ' 'without custom properties') LOG.warn(msg % filename) return {}
def test_replication_dump(self): tempdir = self.useFixture(fixtures.TempDir()).path options = UserDict.UserDict() options.chunksize = 4096 options.mastertoken = 'mastertoken' options.metaonly = False args = ['localhost:9292', tempdir] orig_img_service = glance_replicator.get_image_service self.addCleanup(setattr, glance_replicator, 'get_image_service', orig_img_service) glance_replicator.get_image_service = get_image_service glance_replicator.replication_dump(options, args) for active in [ '5dcddce0-cba5-4f18-9cf4-9853c7b207a6', '37ff82db-afca-48c7-ae0b-ddc7cf83e3db' ]: imgfile = os.path.join(tempdir, active) self.assertTrue(os.path.exists(imgfile)) self.assertTrue(os.path.exists('%s.img' % imgfile)) with open(imgfile) as f: d = jsonutils.loads(f.read()) self.assertIn('status', d) self.assertIn('id', d) self.assertIn('size', d) for inactive in ['f4da1d2a-40e8-4710-b3aa-0222a4cc887b']: imgfile = os.path.join(tempdir, inactive) self.assertTrue(os.path.exists(imgfile)) self.assertFalse(os.path.exists('%s.img' % imgfile)) with open(imgfile) as f: d = jsonutils.loads(f.read()) self.assertIn('status', d) self.assertIn('id', d) self.assertIn('size', d)
def test_create_ensure_expires_at_is_not_returned(self): response = webob.Response() self.serializer.create(response, self.fixtures[0]) serialized_task = jsonutils.loads(response.body) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[0].task_id, serialized_task['id']) self.assertEqual(self.fixtures[0].task_input, serialized_task['input']) self.assertNotIn('expires_at', serialized_task) self.assertEqual('application/json', response.content_type) response = webob.Response() self.serializer.create(response, self.fixtures[1]) serialized_task = jsonutils.loads(response.body) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[1].task_id, serialized_task['id']) self.assertEqual(self.fixtures[1].task_input, serialized_task['input']) self.assertNotIn('expires_at', serialized_task) self.assertEqual('application/json', response.content_type)
def test_delete_image(self): """Tests that the registry API deletes the image""" # Grab the original number of images req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'filters': {'deleted': False}} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) res_dict = jsonutils.loads(res.body)[0] self.assertEqual(res.status_int, 200) orig_num_images = len(res_dict) # Delete image #2 cmd = [{ 'command': 'image_destroy', 'kwargs': {'image_id': UUID2} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) # Verify one less image cmd = [{ 'command': 'image_get_all', 'kwargs': {'filters': {'deleted': False}} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) res_dict = jsonutils.loads(res.body)[0] self.assertEqual(res.status_int, 200) new_num_images = len(res_dict) self.assertEqual(new_num_images, orig_num_images - 1)
def test_scrubber_app(self): """ test that the glance-scrubber script runs successfully when not in daemon mode """ self.cleanup() self.start_servers(delayed_delete=True, daemon=False, metadata_encryption_key='') headers = { 'x-image-meta-name': 'test_image', 'x-image-meta-is_public': 'true', 'x-image-meta-disk_format': 'raw', 'x-image-meta-container_format': 'ovf', 'content-type': 'application/octet-stream', } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', body='XXX', headers=headers) self.assertEqual(response.status, 201) image = jsonutils.loads(content)['image'] self.assertEqual('active', image['status']) image_id = image['id'] path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(response.status, 200) response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 200) self.assertEqual('pending_delete', response['x-image-meta-status']) # wait for the scrub time on the image to pass time.sleep(self.api_server.scrub_time) # scrub images and make sure they get deleted exe_cmd = "%s -m glance.cmd.scrubber" % sys.executable cmd = ("%s --config-file %s" % (exe_cmd, self.scrubber_daemon.conf_file_name)) exitcode, out, err = execute(cmd, raise_error=False) self.assertEqual(0, exitcode) self.wait_for_scrub(path) self.stop_servers()
def test_download_image_with_no_restricted_property_set_to_image(self): """ We test the following sequential series of actions: 0. POST /images with public image named Image1 and no custom properties - Verify 201 returned 1. GET image 2. DELETE image1 - Delete the newly added image """ self.cleanup() rules = {"context_is_admin": "role:admin", "default": "", "restricted": "not ('test_key':%(x_test_key)s and role:_member_)", "download_image": "role:admin or rule:restricted"} self.set_policy_rules(rules) self.start_servers(**self.__dict__.copy()) image_data = "*" * FIVE_KB headers = minimal_headers('Image1') headers.update({'X-Roles': 'member'}) path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers, body=image_data) self.assertEqual(201, response.status) data = jsonutils.loads(content) image_id = data['image']['id'] self.assertEqual(data['image']['checksum'], hashlib.md5(image_data).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], "Image1") self.assertTrue(data['image']['is_public']) # 1. GET image path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(200, response.status) # 2. DELETE image1 path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) http = httplib2.Http() response, content = http.request(path, 'DELETE') self.assertEqual(200, response.status) self.stop_servers()
def test_get_image_members(self): """ Tests members listing for existing images """ req = webob.Request.blank('/rpc') req.method = 'POST' cmd = [{'command': 'image_member_find', 'kwargs': {'image_id': UUID2}}] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) memb_list = jsonutils.loads(res.body)[0] self.assertEqual(len(memb_list), 0)
def test_request(self): api = create_api() req = webob.Request.blank('/rpc') req.method = 'POST' req.body = jsonutils.dumps([{ "command": "get_images", "kwargs": { "keyword": 1 } }]) res = req.get_response(api) returned = jsonutils.loads(res.body) self.assertIsInstance(returned, list) self.assertEqual(returned[0], 1)
def test_create(self): response = webob.Response() self.serializer.create(response, self.fixtures[3]) serialized_task = jsonutils.loads(response.body) self.assertEqual(response.status_int, 201) self.assertEqual(self.fixtures[3]['task'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[3]['task_details'].task_id, serialized_task['id']) self.assertEqual(self.fixtures[3]['task_details'].input, serialized_task['input']) self.assertTrue('expires_at' in serialized_task) self.assertEqual('application/json', response.content_type)
def _check_upload_response_headers(headers, body): """Check that the headers of an upload are reasonable. headers: the headers from the upload body: the body from the upload """ if 'status' not in headers: try: d = jsonutils.loads(body) if 'image' in d and 'status' in d['image']: return except Exception: raise UploadException('Image upload problem: %s' % body)
def _read_policy_file(self): """Read contents of the policy file This re-caches policy data if the file has been changed. """ mtime = os.path.getmtime(self.policy_path) if not self.policy_file_contents or mtime != self.policy_file_mtime: LOG.debug(_("Loading policy from %s") % self.policy_path) with open(self.policy_path) as fap: raw_contents = fap.read() rules_dict = jsonutils.loads(raw_contents) self.policy_file_contents = dict( (k, policy.parse_rule(v)) for k, v in rules_dict.items()) self.policy_file_mtime = mtime return self.policy_file_contents
def test_get_index_sort_container_format_desc(self): """ Tests that the registry API returns list of public images sorted alphabetically by container_format in descending order. """ UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, 'status': 'active', 'is_public': True, 'disk_format': 'ami', 'container_format': 'ami', 'name': 'asdf', 'size': 19, 'checksum': None} db_api.image_create(self.context, extra_fixture) UUID4 = _gen_uuid() extra_fixture = {'id': UUID4, 'status': 'active', 'is_public': True, 'disk_format': 'iso', 'container_format': 'bare', 'name': 'xyz', 'size': 20, 'checksum': None} db_api.image_create(self.context, extra_fixture) req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'sort_key': 'container_format', 'sort_dir': 'desc'} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) res_dict = jsonutils.loads(res.body)[0] images = res_dict self.assertEqual(len(images), 4) self.assertEqual(images[0]['id'], UUID2) self.assertEqual(images[1]['id'], UUID4) self.assertEqual(images[2]['id'], UUID3) self.assertEqual(images[3]['id'], UUID1)
def test_api_response_when_image_deleted_from_filesystem(self): """ A test for LP bug #781410 -- glance should fail more gracefully on requests for images that have been removed from the fs """ self.cleanup() self.start_servers() # 1. POST /images with public image named Image1 # attribute and no custom properties. Verify a 200 OK is returned image_data = "*" * FIVE_KB headers = minimal_headers('Image1') path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers, body=image_data) self.assertEqual(response.status, 201) data = jsonutils.loads(content) self.assertEqual(data['image']['checksum'], hashlib.md5(image_data).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], "Image1") self.assertEqual(data['image']['is_public'], True) # 2. REMOVE the image from the filesystem image_path = "%s/images/%s" % (self.test_dir, data['image']['id']) os.remove(image_path) # 3. HEAD /images/1 # Verify image found now path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, data['image']['id']) http = httplib2.Http() response, content = http.request(path, 'HEAD') self.assertEqual(response.status, 200) self.assertEqual(response['x-image-meta-name'], "Image1") # 4. GET /images/1 # Verify the api throws the appropriate 404 error path = "http://%s:%d/v1/images/1" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 404) self.stop_servers()
def test_request_exc(self): api = create_api() req = webob.Request.blank('/rpc') req.method = 'POST' req.body = jsonutils.dumps([{ "command": "get_all_images", "kwargs": { "keyword": 1 } }]) # Sending non-accepted keyword # to get_all_images method res = req.get_response(api) returned = jsonutils.loads(res.body) self.assertIn("_error", returned[0])
def get_images(self, **kwargs): """ Returns a list of image id/name mappings from Registry :param filters: dict of keys & expected values to filter results :param marker: image id after which to start page :param limit: max number of images to return :param sort_key: results will be ordered by this image attribute :param sort_dir: direction in which to order results (asc, desc) """ params = self._extract_params(kwargs, images.SUPPORTED_PARAMS) res = self.do_request("GET", "/images", params=params) image_list = jsonutils.loads(res.read())['images'] for image in image_list: image = self.decrypt_metadata(image) return image_list
def _post_new_task(self, **kwargs): task_owner = kwargs['owner'] headers = minimal_task_headers(task_owner) task_data = _new_task_fixture() body_content = json.dumps(task_data) path = "/v2/tasks" response, content = self.http.request(path, 'POST', headers=headers, body=body_content) self.assertEqual(response.status, 201) task = json.loads(content) return task
def test_show_unknown(self): """ Tests that the registry API endpoint returns a 404 for an unknown image id """ req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get', 'kwargs': {'image_id': _gen_uuid()}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) res_dict = jsonutils.loads(res.body)[0] self.assertEqual(res_dict["_error"]["cls"], 'glance.common.exception.NotFound')
def test_index_carries_query_parameters(self): url = '/v2/tasks?limit=10&sort_key=id&sort_dir=asc' request = webob.Request.blank(url) response = webob.Response(request=request) task_fixtures = [f for f in self.fixtures] result = {'tasks': task_fixtures, 'next_marker': UUID2} self.serializer.index(response, result) output = jsonutils.loads(response.body) expected_url = '/v2/tasks?limit=10&sort_dir=asc&sort_key=id' self.assertEqual(unit_test_utils.sort_url_by_qs_keys(expected_url), unit_test_utils.sort_url_by_qs_keys(output['first'])) expect_next = '/v2/tasks?limit=10&marker=%s&sort_dir=asc&sort_key=id' self.assertEqual( unit_test_utils.sort_url_by_qs_keys(expect_next % UUID2), unit_test_utils.sort_url_by_qs_keys(output['next']))
def test_update(self): expected = { 'image_id': UUID2, 'member_id': TENANT1, 'status': 'accepted', 'schema': '/v2/schemas/member', 'created_at': ISOTIME, 'updated_at': ISOTIME } request = webob.Request.blank('/v2/images/%s/members/%s' % (UUID2, TENANT1)) response = webob.Response(request=request) result = self.fixtures[0] self.serializer.update(response, result) actual = jsonutils.loads(response.body) self.assertEqual(expected, actual) self.assertEqual('application/json', response.content_type)
def test_get_index_unknown_marker(self): """ Tests that the registry API returns a NotFound when an unknown marker is provided """ req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'marker': _gen_uuid()}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) result = jsonutils.loads(res.body)[0] self.assertIn("_error", result) self.assertIn("NotFound", result["_error"]["cls"])
def test_get_index_limit(self): """ Tests that the registry API returns list of public images that conforms to a limit query param """ UUID3 = _gen_uuid() extra_fixture = {'id': UUID3, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'new name! #123', 'size': 19, 'checksum': None} db_api.image_create(self.context, extra_fixture) UUID4 = _gen_uuid() extra_fixture = {'id': UUID4, 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'new name! #123', 'size': 20, 'checksum': None} db_api.image_create(self.context, extra_fixture) req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'limit': 1}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) res_dict = jsonutils.loads(res.body)[0] self.assertEqual(res.status_int, 200) images = res_dict self.assertEqual(len(images), 1) # expect list to be sorted by created_at desc self.assertEqual(images[0]['id'], UUID4)
def test_get_index_filter_name(self): """ Tests that the registry API returns list of public images that have a specific name. This is really a sanity check, filtering is tested more in-depth using /images/detail """ extra_fixture = {'id': _gen_uuid(), 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'new name! #123', 'size': 19, 'checksum': None} db_api.image_create(self.context, extra_fixture) extra_fixture = {'id': _gen_uuid(), 'status': 'active', 'is_public': True, 'disk_format': 'vhd', 'container_format': 'ovf', 'name': 'new name! #123', 'size': 20, 'checksum': None} db_api.image_create(self.context, extra_fixture) req = webob.Request.blank('/rpc') req.method = "POST" cmd = [{ 'command': 'image_get_all', 'kwargs': {'filters': {'name': 'new name! #123'}}, }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) res_dict = jsonutils.loads(res.body)[0] self.assertEqual(res.status_int, 200) images = res_dict self.assertEqual(len(images), 2) for image in images: self.assertEqual('new name! #123', image['name'])
def fake_do_request(cls, url, method, headers=None, body=None): if (not url.rstrip('/').endswith('v2.0/tokens') or url.count("2.0") != 1): self.fail("Invalid v2.0 token path (%s)" % url) creds = jsonutils.loads(body)['auth'] username = creds['passwordCredentials']['username'] password = creds['passwordCredentials']['password'] tenant = creds['tenantName'] resp = webob.Response() if (username != 'user1' or password != 'pass' or tenant != 'tenant-ok'): resp.status = 401 else: resp.status = 200 body = mock_token.token return FakeResponse(resp), jsonutils.dumps(body)
def test_delete_image_response(self): """Tests that the registry API delete returns the image metadata""" image = self.FIXTURES[0] req = webob.Request.blank('/rpc') req.method = 'POST' cmd = [{ 'command': 'image_destroy', 'kwargs': {'image_id': image['id']} }] req.body = jsonutils.dumps(cmd) res = req.get_response(self.api) self.assertEqual(res.status_int, 200) deleted_image = jsonutils.loads(res.body)[0] self.assertEqual(image['id'], deleted_image['id']) self.assertTrue(deleted_image['deleted']) self.assertTrue(deleted_image['deleted_at'])
def test_cache_remote_image(self): """ We test that caching is no longer broken for remote images """ self.cleanup() self.start_servers(**self.__dict__.copy()) setup_http(self) # Add a remote image and verify a 201 Created is returned remote_uri = get_http_uri(self, '2') headers = { 'X-Image-Meta-Name': 'Image2', 'X-Image-Meta-disk_format': 'raw', 'X-Image-Meta-container_format': 'ovf', 'X-Image-Meta-Is-Public': 'True', 'X-Image-Meta-Location': remote_uri } path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers) self.assertEqual(response.status, 201) data = jsonutils.loads(content) self.assertEqual(data['image']['size'], FIVE_KB) image_id = data['image']['id'] path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id) # Grab the image http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) # Grab the image again to ensure it can be served out from # cache with the correct size http = httplib2.Http() response, content = http.request(path, 'GET') self.assertEqual(response.status, 200) self.assertEqual(int(response['content-length']), FIVE_KB) self.stop_servers()
def test_get(self): expected = { 'id': UUID4, 'type': 'import', 'status': 'failure', 'input': {'loc': 'boo'}, 'result': {}, 'owner': TENANT4, 'message': '', 'created_at': ISOTIME, 'updated_at': ISOTIME, 'expires_at': ISOTIME, 'self': '/v2/tasks/%s' % UUID4, 'schema': '/v2/schemas/task', } response = webob.Response() self.serializer.get(response, self.fixtures[3]) actual = jsonutils.loads(response.body) self.assertEqual(expected, actual) self.assertEqual('application/json', response.content_type)
def add_image(self, name): """ Adds an image and returns the newly-added image identifier """ image_data = "*" * FIVE_KB headers = minimal_headers('%s' % name) path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port) http = httplib2.Http() response, content = http.request(path, 'POST', headers=headers, body=image_data) self.assertEqual(response.status, 201) data = jsonutils.loads(content) self.assertEqual(data['image']['checksum'], hashlib.md5(image_data).hexdigest()) self.assertEqual(data['image']['size'], FIVE_KB) self.assertEqual(data['image']['name'], name) self.assertTrue(data['image']['is_public']) return data['image']['id']
def _format_metadef_object_from_db(self, metadata_object, namespace_entity): required_str = metadata_object['required'] required_list = required_str.split(",") if required_str else [] # Convert the persisted json schema to a dict of PropertyTypes property_types = {} json_props = json.loads(metadata_object['schema']) for id in json_props: property_types[id] = fromjson(PropertyType, json_props[id]) return glance.domain.MetadefObject( namespace=namespace_entity, object_id=metadata_object['id'], name=metadata_object['name'], required=required_list, description=metadata_object['description'], properties=property_types, created_at=metadata_object['created_at'], updated_at=metadata_object['updated_at'])
def add_image(self, image_metadata): """ Tells registry about an image's metadata """ headers = { 'Content-Type': 'application/json', } if 'image' not in image_metadata: image_metadata = dict(image=image_metadata) encrypted_metadata = self.encrypt_metadata(image_metadata['image']) image_metadata['image'] = encrypted_metadata body = jsonutils.dumps(image_metadata) res = self.do_request("POST", "/images", body=body, headers=headers) # Registry returns a JSONified dict(image=image_info) data = jsonutils.loads(res.read()) image = data['image'] return self.decrypt_metadata(image)
def test_get_version_list(self): req = webob.Request.blank('/', base_url='http://127.0.0.1:9292/') req.accept = 'application/json' self.config(bind_host='127.0.0.1', bind_port=9292) res = versions.Controller().index(req) self.assertEqual(res.status_int, 300) self.assertEqual(res.content_type, 'application/json') results = jsonutils.loads(res.body)['versions'] expected = [ { 'id': 'v2.2', 'status': 'CURRENT', 'links': [{'rel': 'self', 'href': 'http://127.0.0.1:9292/v2/'}], }, { 'id': 'v2.1', 'status': 'SUPPORTED', 'links': [{'rel': 'self', 'href': 'http://127.0.0.1:9292/v2/'}], }, { 'id': 'v2.0', 'status': 'SUPPORTED', 'links': [{'rel': 'self', 'href': 'http://127.0.0.1:9292/v2/'}], }, { 'id': 'v1.1', 'status': 'CURRENT', 'links': [{'rel': 'self', 'href': 'http://127.0.0.1:9292/v1/'}], }, { 'id': 'v1.0', 'status': 'SUPPORTED', 'links': [{'rel': 'self', 'href': 'http://127.0.0.1:9292/v1/'}], }, ] self.assertEqual(results, expected)