def test_add_clear(self): """ We test the following: 1. Add a couple images with metadata 2. Clear the images 3. Verify no public images found 4. Run SQL against DB to verify no undeleted properties """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 1. Add some images for i in range(1, 5): cmd = "bin/glance --port=%d add is_public=True name=MyName " \ " foo=bar" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Added new image with ID: %i' % i, out.strip()) # 2. Clear all images cmd = "bin/glance --port=%d --force clear" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) # 3. Verify no public images are found cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\n") first_line = lines[0] self.assertEqual('No public images found.', first_line) # 4. Lastly we manually verify with SQL that image properties are # also getting marked as deleted. sql = "SELECT COUNT(*) FROM image_properties WHERE deleted = 0" recs = self.run_sql_cmd(sql) for rec in recs: self.assertEqual(0, rec[0]) self.stop_servers()
def start(self, **kwargs): """ Starts the server. Any kwargs passed to this method will override the configuration value in the conf file used in starting the servers. """ if self.conf_file: raise RuntimeError("Server configuration file already exists!") if not self.conf_base: raise RuntimeError("Subclass did not populate config_base!") conf_override = self.__dict__.copy() if kwargs: conf_override.update(**kwargs) # A config file to use just for this test...we don't want # to trample on currently-running Glance servers, now do we? conf_file = tempfile.NamedTemporaryFile() conf_file.write(self.conf_base % conf_override) conf_file.flush() self.conf_file = conf_file self.conf_file_name = conf_file.name cmd = ("./bin/glance-control %(server_name)s start " "%(conf_file_name)s --pid-file=%(pid_file)s" % self.__dict__) return execute(cmd)
def _reset_databases(self): for key, engine in self.engines.items(): conn_string = TestMigrations.TEST_DATABASES[key] conn_pieces = urlparse.urlparse(conn_string) if conn_string.startswith('sqlite'): # We can just delete the SQLite database, which is # the easiest and cleanest solution db_path = conn_pieces.path.strip('/') if os.path.exists(db_path): os.unlink(db_path) # No need to recreate the SQLite DB. SQLite will # create it for us if it's not there... elif conn_string.startswith('mysql'): # We can execute the MySQL client to destroy and re-create # the MYSQL database, which is easier and less error-prone # than using SQLAlchemy to do this via MetaData...trust me. database = conn_pieces.path.strip('/') loc_pieces = conn_pieces.netloc.split('@') host = loc_pieces[1] auth_pieces = loc_pieces[0].split(':') user = auth_pieces[0] password = "" if len(auth_pieces) > 1: if auth_pieces[1].strip(): password = "******" % auth_pieces[1] sql = ("drop database if exists %(database)s; " "create database %(database)s;") % locals() cmd = ("mysql -u%(user)s %(password)s -h%(host)s " "-e\"%(sql)s\"") % locals() exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode)
def stop(self): """ Spin down the server. """ cmd = ("./bin/glance-control %(server_name)s stop " "%(conf_file_name)s --pid-file=%(pid_file)s" % self.__dict__) return execute(cmd)
def _do_check(self, name): package_name = 'tests.pwb.' + name script_path = os.path.join(_pwb_tests_dir, name + '.py') direct = execute([sys.executable, '-m', package_name]) vpwb = execute_pwb([script_path]) self.maxDiff = None self.assertEqual(direct['stdout'], vpwb['stdout']) return (direct, vpwb)
def _do_check(self, name): package_name = 'tests.pwb.' + name script_path = join_pwb_tests_path(name + '.py') direct = execute([sys.executable, '-m', package_name]) vpwb = execute_pwb([script_path]) self.maxDiff = None self.assertEqual(direct['stdout'], vpwb['stdout']) return (direct, vpwb)
def testScriptEnvironment(self): """ Test environment of pywikibot. Make sure the environment is not contaminated, and is the same as the environment we get when directly running a script. """ direct = execute([sys.executable, '-m', 'tests.pwb.print_locals']) vpwb = execute_pwb([print_locals_test_script]) self.maxDiff = None self.assertEqual(direct['stdout'], vpwb['stdout'])
def test_delete_not_existing(self): """ We test the following: 0. GET /images/1 - Verify 404 1. DELETE /images/1 - Verify 404 """ if self.skip_tests: return True self.cleanup() self.start_servers(**self.__dict__.copy()) api_port = self.api_port registry_port = self.registry_port # 0. GET /images/1 # Verify 404 returned cmd = "curl -i http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 404 Not Found", status_line) # 1. DELETE /images/1 # Verify 404 returned cmd = "curl -i -X DELETE http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 404 Not Found", status_line) self.stop_servers()
def test_exception_not_eaten_from_registry_to_api(self): """ A test for LP bug #704854 -- Exception thrown by registry server is consumed by API server. We start both servers daemonized. We then use curl to try adding an image that does not meet validation requirements on the registry server and test that the error returned from the API server to curl is appropriate We also fire the glance-upload tool against the API server and verify that glance-upload doesn't eat the exception either... """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port cmd = "curl -g http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) cmd = "curl -X POST -H 'Content-Type: application/octet-stream' "\ "-H 'X-Image-Meta-Name: ImageName' "\ "-H 'X-Image-Meta-Disk-Format: Invalid' "\ "http://0.0.0.0:%d/v1/images" % api_port ignored, out, err = execute(cmd) self.assertTrue('Invalid disk format' in out, "Could not find 'Invalid disk format' " "in output: %s" % out) self.stop_servers()
def test_traceback_not_consumed(self): """ A test that errors coming from the POST API do not get consumed and print the actual error message, and not something like <traceback object at 0x1918d40> :see https://bugs.launchpad.net/glance/+bug/755912 """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # POST /images with binary data, but not setting # Content-Type to application/octet-stream, verify a # 400 returned and that the error is readable. with tempfile.NamedTemporaryFile() as test_data_file: test_data_file.write("XXX") test_data_file.flush() cmd = ("curl -i -X POST --upload-file %s " "http://0.0.0.0:%d/v1/images") % (test_data_file.name, api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines.pop(0) self.assertEqual("HTTP/1.1 400 Bad Request", status_line) expected = "Content-Type must be application/octet-stream" self.assertTrue(expected in out, "Could not find '%s' in '%s'" % (expected, out)) self.stop_servers()
def test_ordered_images(self): """ Set up three test images and ensure each query param filter works """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 1. POST /images with three public images with various attributes cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Status: active' " "-H 'X-Image-Meta-Container-Format: ovf' " "-H 'X-Image-Meta-Disk-Format: vdi' " "-H 'X-Image-Meta-Size: 19' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: ASDF' " "-H 'X-Image-Meta-Status: active' " "-H 'X-Image-Meta-Container-Format: bare' " "-H 'X-Image-Meta-Disk-Format: iso' " "-H 'X-Image-Meta-Size: 2' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: XYZ' " "-H 'X-Image-Meta-Status: saving' " "-H 'X-Image-Meta-Container-Format: ami' " "-H 'X-Image-Meta-Disk-Format: ami' " "-H 'X-Image-Meta-Size: 5' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # 2. GET /images with no query params # Verify three public images sorted by created_at desc cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 3) self.assertEqual(images[0]['id'], 3) self.assertEqual(images[1]['id'], 2) self.assertEqual(images[2]['id'], 1) # 3. GET /images sorted by name asc params = 'sort_key=name&sort_dir=asc' cmd = "curl 'http://0.0.0.0:%d/v1/images?%s'" % (api_port, params) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 3) self.assertEqual(images[0]['id'], 2) self.assertEqual(images[1]['id'], 1) self.assertEqual(images[2]['id'], 3) # 4. GET /images sorted by size desc params = 'sort_key=size&sort_dir=desc' cmd = "curl 'http://0.0.0.0:%d/v1/images?%s'" % (api_port, params) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 3) self.assertEqual(images[0]['id'], 1) self.assertEqual(images[1]['id'], 3) self.assertEqual(images[2]['id'], 2) self.stop_servers()
def test_add_list_delete_list(self): """ We test the following: 0. Verify no public images in index 1. Add a public image with a location attr and no image data 2. Check that image exists in index 3. Delete the image 4. Verify no longer in index """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) # 1. Add public image cmd = "bin/glance --port=%d add is_public=True name=MyImage" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Added new image with ID: 1', out.strip()) # 2. Verify image added as public image cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\n") first_line = lines[0] image_data_line = lines[3] self.assertEqual('Found 1 public images...', first_line) self.assertTrue('MyImage' in image_data_line) # 3. Delete the image cmd = "bin/glance --port=%d --force delete 1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Deleted image 1', out.strip()) # 4. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) self.stop_servers()
def test_add_list_update_list(self): """ Test for LP Bugs #736295, #767203 We test the following: 0. Verify no public images in index 1. Add a NON-public image 2. Check that image does not appear in index 3. Update the image to be public 4. Check that image now appears in index 5. Update the image's Name attribute 6. Verify the updated name is shown """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) # 1. Add public image cmd = "bin/glance --port=%d add name=MyImage" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Added new image with ID: 1', out.strip()) # 2. Verify image does not appear as a public image cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) # 3. Update the image to make it public cmd = "bin/glance --port=%d update 1 is_public=True" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Updated image 1', out.strip()) # 4. Verify image 1 in list of public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\n") first_line = lines[0] self.assertEqual('Found 1 public images...', first_line) image_data_line = lines[3] self.assertTrue('MyImage' in image_data_line) # 5. Update the image's Name attribute updated_image_name = "Updated image name" cmd = "bin/glance --port=%d update 1 is_public=True name=\"%s\"" \ % (api_port, updated_image_name) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('Updated image 1', out.strip()) # 6. Verify updated name shown cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(updated_image_name in out, "%s not found in %s" % (updated_image_name, out)) self.stop_servers()
def test_limited_images(self): """ Ensure marker and limit query params work """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 1. POST /images with three public images with various attributes cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image2' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image3' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # 2. GET /images with limit of 2 # Verify only two images were returned cmd = "curl http://0.0.0.0:%d/v1/images?limit=2" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 2) self.assertEqual(int(images[0]['id']), 3) self.assertEqual(int(images[1]['id']), 2) # 3. GET /images with marker # Verify only two images were returned cmd = "curl http://0.0.0.0:%d/v1/images?marker=3" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 2) self.assertEqual(int(images[0]['id']), 2) self.assertEqual(int(images[1]['id']), 1) # 4. GET /images with marker and limit # Verify only one image was returned with the correct id cmd = ("curl 'http://0.0.0.0:%d/v1/images?" "limit=1&marker=2'" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 1) self.assertEqual(int(images[0]['id']), 1) # 5. GET /images/detail with marker and limit # Verify only one image was returned with the correct id cmd = ("curl 'http://0.0.0.0:%d/v1/images/detail?" "limit=1&marker=3'" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip())['images'] self.assertEqual(len(images), 1) self.assertEqual(int(images[0]['id']), 2) self.stop_servers()
def test_killed_image_not_in_index(self): """ We test conditions that produced LP Bug #768969, where an image in the 'killed' status is displayed in the output of glance index, and the status column is not displayed in the output of glance show <ID>. Start servers with Swift backend and a bad auth URL, and then: 0. Verify no public images in index 1. Attempt to add an image 2. Verify the image does NOT appear in the index output 3. Verify the status of the image is displayed in the show output and is in status 'killed' """ self.cleanup() # Start servers with a Swift backend and a bad auth URL options = {'default_store': 'swift', 'swift_store_auth_address': 'badurl'} self.start_servers(**options) api_port = self.api_port registry_port = self.registry_port # 0. Verify no public images cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) # 1. Attempt to add an image with tempfile.NamedTemporaryFile() as image_file: image_file.write("XXX") image_file.flush() image_file_name = image_file.name cmd = ("bin/glance --port=%d add name=Jonas is_public=True " "disk_format=qcow2 container_format=bare < %s" % (api_port, image_file_name)) exitcode, out, err = execute(cmd, raise_error=False) self.assertNotEqual(0, exitcode) self.assertTrue('Failed to add image.' in out) # 2. Verify image does not appear as public image cmd = "bin/glance --port=%d index" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('No public images found.', out.strip()) # 3. Verify image status in show is 'killed' cmd = "bin/glance --port=%d show 1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue('Status: killed' in out) self.stop_servers()
def test_get_head_simple_post(self): """ We test the following sequential series of actions: 0. GET /images - Verify no public images 1. GET /images/detail - Verify no public images 2. HEAD /images/1 - Verify 404 returned 3. POST /images with public image named Image1 with a location attribute and no custom properties - Verify 201 returned 4. HEAD /images/1 - Verify HTTP headers have correct information we just added 5. GET /images/1 - Verify all information on image we just added is correct 6. GET /images - Verify the image we just added is returned 7. GET /images/detail - Verify the image we just added is returned 8. PUT /images/1 with custom properties of "distro" and "arch" - Verify 200 returned 9. GET /images/1 - Verify updated information about image was stored 10. PUT /images/1 - Remove a previously existing property. 11. PUT /images/1 - Add a previously deleted property. """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 1. GET /images/detail # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 2. HEAD /images/1 # Verify 404 returned cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 404 Not Found", status_line) # 3. POST /images with public image named Image1 # attribute and no custom properties. Verify a 200 OK is returned image_data = "*" * FIVE_KB cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'Content-Type: application/octet-stream' " "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Is-Public: True' " "--data-binary \"%s\" " "http://0.0.0.0:%d/v1/images") % (image_data, api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # 4. HEAD /images # Verify image found now cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) self.assertTrue("X-Image-Meta-Name: Image1" in out) # 5. GET /images/1 # Verify all information on image we just added is correct cmd = "curl -i http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") self.assertEqual("HTTP/1.1 200 OK", lines.pop(0)) # Handle the headers image_headers = {} std_headers = {} other_lines = [] for line in lines: if line.strip() == '': continue if line.startswith("X-Image"): pieces = line.split(":") key = pieces[0].strip() value = ":".join(pieces[1:]).strip() image_headers[key] = value elif ':' in line: pieces = line.split(":") key = pieces[0].strip() value = ":".join(pieces[1:]).strip() std_headers[key] = value else: other_lines.append(line) expected_image_headers = { 'X-Image-Meta-Id': '1', 'X-Image-Meta-Name': 'Image1', 'X-Image-Meta-Is_public': 'True', 'X-Image-Meta-Status': 'active', 'X-Image-Meta-Disk_format': '', 'X-Image-Meta-Container_format': '', 'X-Image-Meta-Size': str(FIVE_KB), 'X-Image-Meta-Location': 'file://%s/1' % self.api_server.image_dir} expected_std_headers = { 'Content-Length': str(FIVE_KB), 'Content-Type': 'application/octet-stream'} for expected_key, expected_value in expected_image_headers.items(): self.assertTrue(expected_key in image_headers, "Failed to find key %s in image_headers" % expected_key) self.assertEqual(expected_value, image_headers[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, image_headers[expected_key])) for expected_key, expected_value in expected_std_headers.items(): self.assertTrue(expected_key in std_headers, "Failed to find key %s in std_headers" % expected_key) self.assertEqual(expected_value, std_headers[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, std_headers[expected_key])) # Now the image data... expected_image_data = "*" * FIVE_KB # Should only be a single "line" left, and # that's the image data self.assertEqual(1, len(other_lines)) self.assertEqual(expected_image_data, other_lines[0]) # 6. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_result = {"images": [ {"container_format": None, "disk_format": None, "id": 1, "name": "Image1", "checksum": "c2e5db72bd7fd153f53ede5da5a06de3", "size": 5120}]} self.assertEqual(expected_result, json.loads(out.strip())) # 7. GET /images/detail # Verify image and all its metadata cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_image = { "status": "active", "name": "Image1", "deleted": False, "container_format": None, "disk_format": None, "id": 1, "location": "file://%s/1" % self.api_server.image_dir, "is_public": True, "deleted_at": None, "properties": {}, "size": 5120} image = json.loads(out.strip())['images'][0] for expected_key, expected_value in expected_image.items(): self.assertTrue(expected_key in image, "Failed to find key %s in image" % expected_key) self.assertEqual(expected_value, expected_image[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, image[expected_key])) # 8. PUT /images/1 with custom properties of "distro" and "arch" # Verify 200 returned cmd = ("curl -i -X PUT " "-H 'X-Image-Meta-Property-Distro: Ubuntu' " "-H 'X-Image-Meta-Property-Arch: x86_64' " "http://0.0.0.0:%d/v1/images/1") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) # 9. GET /images/detail # Verify image and all its metadata cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) expected_image = { "status": "active", "name": "Image1", "deleted": False, "container_format": None, "disk_format": None, "id": 1, "location": "file://%s/1" % self.api_server.image_dir, "is_public": True, "deleted_at": None, "properties": {'distro': 'Ubuntu', 'arch': 'x86_64'}, "size": 5120} image = json.loads(out.strip())['images'][0] for expected_key, expected_value in expected_image.items(): self.assertTrue(expected_key in image, "Failed to find key %s in image" % expected_key) self.assertEqual(expected_value, image[expected_key], "For key '%s' expected header value '%s'. Got '%s'" % (expected_key, expected_value, image[expected_key])) # 10. PUT /images/1 and remove a previously existing property. cmd = ("curl -i -X PUT " "-H 'X-Image-Meta-Property-Arch: x86_64' " "http://0.0.0.0:%d/v1/images/1") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) image = json.loads(out.strip())['images'][0] self.assertEqual(1, len(image['properties'])) self.assertEqual('x86_64', image['properties']['arch']) # 11. PUT /images/1 and add a previously deleted property. cmd = ("curl -i -X PUT " "-H 'X-Image-Meta-Property-Distro: Ubuntu' " "-H 'X-Image-Meta-Property-Arch: x86_64' " "http://0.0.0.0:%d/v1/images/1") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) cmd = "curl http://0.0.0.0:%d/v1/images/detail" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) image = json.loads(out.strip())['images'][0] self.assertEqual(2, len(image['properties'])) self.assertEqual('x86_64', image['properties']['arch']) self.assertEqual('Ubuntu', image['properties']['distro']) self.stop_servers()
def test_queued_process_flow(self): """ We test the process flow where a user registers an image with Glance but does not immediately upload an image file. Later, the user uploads an image file using a PUT operation. We track the changing of image status throughout this process. 0. GET /images - Verify no public images 1. POST /images with public image named Image1 with no location attribute and no image data. - Verify 201 returned 2. GET /images - Verify one public image 3. HEAD /images/1 - Verify image now in queued status 4. PUT /images/1 with image data - Verify 200 returned 5. HEAD /images/1 - Verify image now in active status 6. GET /images - Verify one public image """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 1. POST /images with public image named Image1 # with no location or image data cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # 2. GET /images # Verify 1 public image cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) image = json.loads(out.strip())['images'][0] expected = {"name": "Image1", "container_format": None, "disk_format": None, "checksum": None, "id": 1, "size": 0} self.assertEqual(expected, image) # 3. HEAD /images # Verify status is in queued cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) self.assertTrue("X-Image-Meta-Name: Image1" in out) self.assertTrue("X-Image-Meta-Status: queued" in out) # 4. PUT /images/1 with image data, verify 200 returned image_data = "*" * FIVE_KB cmd = ("curl -i -X PUT " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'Content-Type: application/octet-stream' " "--data-binary \"%s\" " "http://0.0.0.0:%d/v1/images/1") % (image_data, api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) # 5. HEAD /images # Verify status is in active cmd = "curl -i -X HEAD http://0.0.0.0:%d/v1/images/1" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) self.assertTrue("X-Image-Meta-Name: Image1" in out) self.assertTrue("X-Image-Meta-Status: active" in out) # 6. GET /images # Verify 1 public image still... cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) image = json.loads(out.strip())['images'][0] expected = {"name": "Image1", "container_format": None, "disk_format": None, "checksum": 'c2e5db72bd7fd153f53ede5da5a06de3', "id": 1, "size": 5120} self.assertEqual(expected, image) self.stop_servers()
def test_filtered_images(self): """ Set up three test images and ensure each query param filter works """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 0. GET /images # Verify no public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual('{"images": []}', out.strip()) # 1. POST /images with three public images with various attributes cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Status: active' " "-H 'X-Image-Meta-Container-Format: ovf' " "-H 'X-Image-Meta-Disk-Format: vdi' " "-H 'X-Image-Meta-Size: 19' " "-H 'X-Image-Meta-Is-Public: True' " "-H 'X-Image-Meta-Property-pants: are on' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: My Image!' " "-H 'X-Image-Meta-Status: active' " "-H 'X-Image-Meta-Container-Format: ovf' " "-H 'X-Image-Meta-Disk-Format: vhd' " "-H 'X-Image-Meta-Size: 20' " "-H 'X-Image-Meta-Is-Public: True' " "-H 'X-Image-Meta-Property-pants: are on' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Name: My Image!' " "-H 'X-Image-Meta-Status: saving' " "-H 'X-Image-Meta-Container-Format: ami' " "-H 'X-Image-Meta-Disk-Format: ami' " "-H 'X-Image-Meta-Size: 21' " "-H 'X-Image-Meta-Is-Public: True' " "-H 'X-Image-Meta-Property-pants: are off' " "http://0.0.0.0:%d/v1/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # 2. GET /images # Verify three public images cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 3) # 3. GET /images with name filter # Verify correct images returned with name cmd = "curl http://0.0.0.0:%d/v1/images?name=My%%20Image!" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 2) for image in images["images"]: self.assertEqual(image["name"], "My Image!") # 4. GET /images with status filter # Verify correct images returned with status cmd = ("curl http://0.0.0.0:%d/v1/images/detail?status=queued" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 3) for image in images["images"]: self.assertEqual(image["status"], "queued") cmd = ("curl http://0.0.0.0:%d/v1/images/detail?status=active" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 0) # 5. GET /images with container_format filter # Verify correct images returned with container_format cmd = ("curl http://0.0.0.0:%d/v1/images?container_format=ovf" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 2) for image in images["images"]: self.assertEqual(image["container_format"], "ovf") # 6. GET /images with disk_format filter # Verify correct images returned with disk_format cmd = ("curl http://0.0.0.0:%d/v1/images?disk_format=vdi" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 1) for image in images["images"]: self.assertEqual(image["disk_format"], "vdi") # 7. GET /images with size_max filter # Verify correct images returned with size <= expected cmd = ("curl http://0.0.0.0:%d/v1/images?size_max=20" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 2) for image in images["images"]: self.assertTrue(image["size"] <= 20) # 8. GET /images with size_min filter # Verify correct images returned with size >= expected cmd = ("curl http://0.0.0.0:%d/v1/images?size_min=20" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 2) for image in images["images"]: self.assertTrue(image["size"] >= 20) # 9. GET /images with property filter # Verify correct images returned with property cmd = ("curl http://0.0.0.0:%d/v1/images/detail?" "property-pants=are%%20on" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 2) for image in images["images"]: self.assertEqual(image["properties"]["pants"], "are on") # 10. GET /images with property filter and name filter # Verify correct images returned with property and name # Make sure you quote the url when using more than one param! cmd = ("curl 'http://0.0.0.0:%d/v1/images/detail?" "name=My%%20Image!&property-pants=are%%20on'" % api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) images = json.loads(out.strip()) self.assertEqual(len(images["images"]), 1) for image in images["images"]: self.assertEqual(image["properties"]["pants"], "are on") self.assertEqual(image["name"], "My Image!") self.stop_servers()
def test_version_variations(self): """ We test that various calls to the images and root endpoints are handled properly, and that usage of the Accept: header does content negotiation properly. """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port versions = {'versions': [{ "id": "v1.0", "status": "CURRENT", "links": [{ "rel": "self", "href": "http://0.0.0.0:%d/v1/" % api_port}]}]} versions_json = json.dumps(versions) images = {'images': []} images_json = json.dumps(images) def validate_versions(response_text): """ Returns True if supplied response text contains an appropriate 300 Multiple Choices and has the correct versions output. """ status_line = response_text.split("\r\n")[0] body = response_text[response_text.index("\r\n\r\n") + 1:].strip() return ("HTTP/1.1 300 Multiple Choices" == status_line and versions_json == body) # 0. GET / with no Accept: header # Verify version choices returned. cmd = "curl -i http://0.0.0.0:%d/" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 1. GET /images with no Accept: header # Verify version choices returned. cmd = "curl -i http://0.0.0.0:%d/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 2. GET /v1/images with no Accept: header # Verify empty images list returned. cmd = "curl http://0.0.0.0:%d/v1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual(images_json, out.strip()) # 3. GET / with Accept: unknown header # Verify version choices returned. Verify message in API log about # unknown accept header. cmd = "curl -i -H 'Accept: unknown' http://0.0.0.0:%d/" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) self.assertTrue('Unknown accept header' in open(self.api_server.log_file).read()) # 5. GET / with an Accept: application/vnd.openstack.images-v1 # Verify empty image list returned cmd = ("curl -H 'Accept: application/vnd.openstack.images-v1' " "http://0.0.0.0:%d/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual(images_json, out.strip()) # 5. GET /images with a Accept: application/vnd.openstack.compute-v1 # header. Verify version choices returned. Verify message in API log # about unknown accept header. cmd = ("curl -i -H 'Accept: application/vnd.openstack.compute-v1' " "http://0.0.0.0:%d/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) api_log_text = open(self.api_server.log_file).read() self.assertTrue('Unknown accept header' in api_log_text) # 6. GET /v1.0/images with no Accept: header # Verify empty image list returned cmd = "curl http://0.0.0.0:%d/v1.0/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual(images_json, out.strip()) # 7. GET /v1.a/images with no Accept: header # Verify empty image list returned cmd = "curl http://0.0.0.0:%d/v1.a/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertEqual(images_json, out.strip()) # 8. GET /va.1/images with no Accept: header # Verify version choices returned cmd = "curl -i http://0.0.0.0:%d/va.1/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 9. GET /versions with no Accept: header # Verify version choices returned cmd = "curl -i http://0.0.0.0:%d/versions" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 10. GET /versions with a Accept: application/vnd.openstack.images-v1 # header. Verify version choices returned. cmd = ("curl -i -H 'Accept: application/vnd.openstack.images-v1' " "http://0.0.0.0:%d/versions") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 11. GET /v1/versions with no Accept: header # Verify 404 returned cmd = "curl -i http://0.0.0.0:%d/v1/versions" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) status_line = out.split("\r\n")[0] self.assertEquals("HTTP/1.1 404 Not Found", status_line) # 12. GET /v2/versions with no Accept: header # Verify version choices returned cmd = "curl -i http://0.0.0.0:%d/v2/versions" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) # 13. GET /images with a Accept: application/vnd.openstack.compute-v2 # header. Verify version choices returned. Verify message in API log # about unknown version in accept header. cmd = ("curl -i -H 'Accept: application/vnd.openstack.images-v2' " "http://0.0.0.0:%d/images") % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) api_log_text = open(self.api_server.log_file).read() self.assertTrue('Unknown version in accept header' in api_log_text) # 14. GET /v1.2/images with no Accept: header # Verify version choices returned cmd = "curl -i http://0.0.0.0:%d/v1.2/images" % api_port exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) self.assertTrue(validate_versions(out)) api_log_text = open(self.api_server.log_file).read() self.assertTrue('Unknown version in versioned URI' in api_log_text) self.stop_servers()
def test_size_greater_2G_mysql(self): """ A test against the actual datastore backend for the registry to ensure that the image size property is not truncated. :see https://bugs.launchpad.net/glance/+bug/739433 """ self.cleanup() self.start_servers() api_port = self.api_port registry_port = self.registry_port # 1. POST /images with public image named Image1 # attribute and a size of 5G. Use the HTTP engine with an # X-Image-Meta-Location attribute to make Glance forego # "adding" the image data. # Verify a 200 OK is returned cmd = ("curl -i -X POST " "-H 'Expect: ' " # Necessary otherwise sends 100 Continue "-H 'X-Image-Meta-Location: http://example.com/fakeimage' " "-H 'X-Image-Meta-Size: %d' " "-H 'X-Image-Meta-Name: Image1' " "-H 'X-Image-Meta-Is-Public: True' " "http://0.0.0.0:%d/v1/images") % (FIVE_GB, api_port) exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 201 Created", status_line) # Get the ID of the just-added image. This may NOT be 1, since the # database in the environ variable TEST_GLANCE_CONNECTION may not # have been cleared between test cases... :( new_image_uri = None for line in lines: if line.startswith('Location:'): new_image_uri = line[line.find(':') + 1:].strip() self.assertTrue(new_image_uri is not None, "Could not find a new image URI!") self.assertTrue("v1/images" in new_image_uri, "v1/images not in %s" % new_image_uri) # 2. HEAD /images # Verify image size is what was passed in, and not truncated cmd = "curl -i -X HEAD %s" % new_image_uri exitcode, out, err = execute(cmd) self.assertEqual(0, exitcode) lines = out.split("\r\n") status_line = lines[0] self.assertEqual("HTTP/1.1 200 OK", status_line) self.assertTrue("X-Image-Meta-Size: %d" % FIVE_GB in out, "Size was supposed to be %d. Got:\n%s." % (FIVE_GB, out)) self.stop_servers()