Ejemplo n.º 1
0
    def test_cache_middleware_trans_v1_without_download_image_policy(self):
        """
        Ensure the image v1 API image transfer applied 'download_image'
        policy enforcement.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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(201, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(
            hashlib.md5(image_data).hexdigest(), data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # 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
        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(403, response.status)

        # Now, we delete the image from the server and verify that
        # the image cache no longer contains the deleted 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, 'DELETE')
        self.assertEqual(200, response.status)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 2
0
    def test_cache_middleware_trans_v1_without_download_image_policy(self):
        """
        Ensure the image v1 API image transfer applied 'download_image'
        policy enforcement.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # 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
        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(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/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)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 3
0
    def test_checksum_32_chars_at_image_create(self):
        self.cleanup()
        self.start_servers(**self.__dict__.copy())
        headers = minimal_headers('Image1')
        image_data = "*" * FIVE_KB

        # checksum can be no longer that 32 characters (String(32))
        headers['X-Image-Meta-Checksum'] = 'x' * 42
        content = self._check_image_create(headers, http_client.BAD_REQUEST)
        self.assertIn("Invalid checksum", content)
        # test positive case as well
        headers['X-Image-Meta-Checksum'] = hashlib.md5(image_data).hexdigest()
        self._check_image_create(headers)
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
    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 = json.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 apropriate 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()
Ejemplo n.º 7
0
 def _push_image(self, name=1):
     # First, we need to push an image up
     image_data = "*" * FIVE_KB
     headers = minimal_headers(str(name), public=False)
     path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
     response, content = self._request(path, 'POST',
                                       keystone_utils.pattieblack_token,
                                       headers=headers,
                                       body=image_data)
     self.assertEqual(response.status, 201)
     data = json.loads(content)
     self.assertEqual(data['image']['size'], FIVE_KB)
     self.assertEqual(data['image']['name'], str(name))
     self.assertEqual(data['image']['is_public'], False)
     self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)
     return content
 def add_image(self, name):
     """
     Adds an image with supplied name and returns the newly-created
     image identifier.
     """
     image_data = "*" * FIVE_KB
     headers = minimal_headers(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(201, response.status)
     data = jsonutils.loads(content)
     self.assertEqual(hashlib.md5(image_data).hexdigest(), data["image"]["checksum"])
     self.assertEqual(FIVE_KB, data["image"]["size"])
     self.assertEqual(name, data["image"]["name"])
     self.assertTrue(data["image"]["is_public"])
     return data["image"]["id"]
Ejemplo n.º 9
0
    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.assertTrue(data['image']['is_public'])

        # 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()
Ejemplo n.º 10
0
    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.assertEqual(data["image"]["is_public"], True)
        return data["image"]["id"]
Ejemplo n.º 11
0
 def test_param_int_too_large_at_create(self):
     # currently 2 params min_disk/min_ram can cause DBError on save
     self.cleanup()
     self.start_servers(**self.__dict__.copy())
     # Integer field can't be greater than max 8-byte signed integer
     for param in ['min_disk', 'min_ram']:
         headers = minimal_headers('Image1')
         # check that long numbers result in 400
         headers['X-Image-Meta-%s' % param] = str(sys.maxint + 1)
         content = self._check_image_create(headers, 400)
         self.assertIn("'%s' value out of range" % param, content)
         # check that integers over 4 byte result in 400
         headers['X-Image-Meta-%s' % param] = str(2**31)
         content = self._check_image_create(headers, 400)
         self.assertIn("'%s' value out of range" % param, content)
         # verify positive case as well
         headers['X-Image-Meta-%s' % param] = str((2**31) - 1)
         self._check_image_create(headers)
Ejemplo n.º 12
0
 def test_param_int_too_large_at_create(self):
     # currently 2 params min_disk/min_ram can cause DBError on save
     self.cleanup()
     self.start_servers(**self.__dict__.copy())
     # Integer field can't be greater than max 8-byte signed integer
     for param in ["min_disk", "min_ram"]:
         headers = minimal_headers("Image1")
         # check that long numbers result in 400
         headers["X-Image-Meta-%s" % param] = str(sys.maxint + 1)
         content = self._check_image_create(headers, 400)
         self.assertIn("'%s' value out of range" % param, content)
         # check that integers over 4 byte result in 400
         headers["X-Image-Meta-%s" % param] = str(2 ** 31)
         content = self._check_image_create(headers, 400)
         self.assertIn("'%s' value out of range" % param, content)
         # verify positive case as well
         headers["X-Image-Meta-%s" % param] = str((2 ** 31) - 1)
         self._check_image_create(headers)
 def add_image(self, name):
     """
     Adds an image with supplied name and returns the newly-created
     image identifier.
     """
     image_data = "*" * FIVE_KB
     headers = minimal_headers(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.assertEqual(data['image']['is_public'], True)
     return data['image']['id']
Ejemplo n.º 14
0
 def add_image(self, name):
     """
     Adds an image with supplied name and returns the newly-created
     image identifier.
     """
     image_data = "*" * FIVE_KB
     headers = minimal_headers(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(201, response.status)
     data = jsonutils.loads(content)
     self.assertEqual(hashlib.md5(image_data).hexdigest(),
                      data['image']['checksum'])
     self.assertEqual(FIVE_KB, data['image']['size'])
     self.assertEqual(name, data['image']['name'])
     self.assertTrue(data['image']['is_public'])
     return data['image']['id']
Ejemplo n.º 15
0
    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 = json.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.assertEqual(data['image']['is_public'], True)
        return data['image']['id']
Ejemplo n.º 16
0
    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(201, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual(name, data['image']['name'])
        self.assertTrue(data['image']['is_public'])
        return data['image']['id']
Ejemplo n.º 17
0
    def test_download_non_exists_image_raises_http_forbidden(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. HEAD image
               - Verify HTTP headers have correct information we just added
            2. GET image
               - Verify all information on image we just added is correct
            3. DELETE image1
               - Delete the newly added image
            4. GET image
               - Verify that 403 HTTPForbidden exception is raised prior to
                 404 HTTPNotFound

        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        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(http_client.CREATED, response.status)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        # 1. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual("Image1", response['x-image-meta-name'])

        # 2. GET /images
        # Verify one public image
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(http_client.OK, response.status)

        expected_result = {"images": [
            {"container_format": "ovf",
             "disk_format": "raw",
             "id": image_id,
             "name": "Image1",
             "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
             "size": 5120}]}
        self.assertEqual(expected_result, jsonutils.loads(content))

        # 3. 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(http_client.OK, response.status)

        # 4. GET image
        # Verify that 403 HTTPForbidden exception is raised prior to
        # 404 HTTPNotFound
        rules = {"download_image": '!'}
        self.set_policy_rules(rules)
        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(http_client.FORBIDDEN, response.status)

        self.stop_servers()
Ejemplo n.º 18
0
    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. POST /images with public image named Image1
        and no custom properties
        - Verify 201 returned
        3. HEAD image
        - Verify HTTP headers have correct information we just added
        4. GET image
        - Verify all information on image we just added is correct
        5. GET /images
        - Verify the image we just added is returned
        6. GET /images/detail
        - Verify the image we just added is returned
        7. PUT image with custom properties of "distro" and "arch"
        - Verify 200 returned
        8. PUT image with too many custom properties
        - Verify 413 returned
        9. GET image
        - Verify updated information about image was stored
        10. PUT image
        - Remove a previously existing property.
        11. PUT image
        - Add a previously deleted property.
        12. PUT image/members/member1
        - Add member1 to image
        13. PUT image/members/member2
        - Add member2 to image
        14. GET image/members
        - List image members
        15. DELETE image/members/member1
        - Delete image member1
        16. PUT image/members
        - Attempt to replace members with an overlimit amount
        17. PUT image/members/member11
        - Attempt to add a member while at limit
        18. POST /images with another public image named Image2
        - attribute and three custom properties, "distro", "arch" & "foo"
        - Verify a 200 OK is returned
        19. HEAD image2
        - Verify image2 found now
        20. GET /images
        - Verify 2 public images
        21. GET /images with filter on user-defined property "distro".
        - Verify both images are returned
        22. GET /images with filter on user-defined property 'distro' but
        - with non-existent value. Verify no images are returned
        23. GET /images with filter on non-existent user-defined property
        - "boo". Verify no images are returned
        24. GET /images with filter 'arch=i386'
        - Verify only image2 is returned
        25. GET /images with filter 'arch=x86_64'
        - Verify only image1 is returned
        26. GET /images with filter 'foo=bar'
        - Verify only image2 is returned
        27. DELETE image1
        - Delete image
        28. GET image/members
        -  List deleted image members
        29. PUT image/members/member2
        - Update existing member2 of deleted image
        30. PUT image/members/member3
        - Add member3 to deleted image
        31. DELETE image/members/member2
        - Delete member2 from deleted image
        32. DELETE image2
        - Delete image
        33. GET /images
        - Verify no images are listed
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 0. GET /images
        # Verify no public images
        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)
        self.assertEqual(content, '{"images": []}')

        # 1. GET /images/detail
        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 2. 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)
        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'])

        # 3. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              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 image
        # Verify all information on image we just added is correct
        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(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_KB)}

        expected_std_headers = {
            'content-length': str(FIVE_KB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # 5. GET /images
        # Verify one public image
        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)

        expected_result = {"images": [
            {"container_format": "ovf",
             "disk_format": "raw",
             "id": image_id,
             "name": "Image1",
             "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
             "size": 5120}]}
        self.assertEqual(jsonutils.loads(content), expected_result)

        # 6. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {},
            "size": 5120}

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(expected_value, image['images'][0][expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           image['images'][0][expected_key]))

        # 7. PUT image with custom properties of "distro" and "arch"
        # Verify 200 returned
        headers = {'X-Image-Meta-Property-Distro': 'Ubuntu',
                   'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(data['image']['properties']['arch'], "x86_64")
        self.assertEqual(data['image']['properties']['distro'], "Ubuntu")

        # 8. PUT image with too many custom properties
        # Verify 413 returned
        headers = {}
        for i in range(11):  # configured limit is 10
            headers['X-Image-Meta-Property-foo%d' % i] = 'bar'
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 413)

        # 9. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {'distro': 'Ubuntu', 'arch': 'x86_64'},
            "size": 5120}

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(expected_value, image['images'][0][expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           image['images'][0][expected_key]))

        # 10. PUT image and remove a previously existing property.
        headers = {'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 1)
        self.assertEqual(data['properties']['arch'], "x86_64")

        # 11. PUT image and add a previously deleted property.
        headers = {'X-Image-Meta-Property-Distro': 'Ubuntu',
                   'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 2)
        self.assertEqual(data['properties']['arch'], "x86_64")
        self.assertEqual(data['properties']['distro'], "Ubuntu")
        self.assertNotEqual(data['created_at'], data['updated_at'])

        # 12. Add member to image
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 204)

        # 13. Add member to image
        path = ("http://%s:%d/v1/images/%s/members/pattiewhite" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 204)

        # 14. List image members
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['members']), 2)
        self.assertEqual(data['members'][0]['member_id'], 'pattieblack')
        self.assertEqual(data['members'][1]['member_id'], 'pattiewhite')

        # 15. Delete image member
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 204)

        # 16. Attempt to replace members with an overlimit amount
        # Adding 11 image members should fail since configured limit is 10
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        memberships = []
        for i in range(11):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 413)

        # 17. Attempt to add a member while at limit
        # Adding an 11th member should fail since configured limit is 10
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        memberships = []
        for i in range(10):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 204)

        path = ("http://%s:%d/v1/images/%s/members/fail_me" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 413)

        # 18. POST /images with another public image named Image2
        # attribute and three custom properties, "distro", "arch" & "foo".
        # Verify a 200 OK is returned
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image2')
        headers['X-Image-Meta-Property-Distro'] = 'Ubuntu'
        headers['X-Image-Meta-Property-Arch'] = 'i386'
        headers['X-Image-Meta-Property-foo'] = 'bar'
        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)
        image2_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'], "Image2")
        self.assertTrue(data['image']['is_public'])
        self.assertEqual(data['image']['properties']['distro'], 'Ubuntu')
        self.assertEqual(data['image']['properties']['arch'], 'i386')
        self.assertEqual(data['image']['properties']['foo'], 'bar')

        # 19. HEAD image2
        # Verify image2 found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image2_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image2")

        # 20. GET /images
        # Verify 2 public images
        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)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 2)
        self.assertEqual(images[0]['id'], image2_id)
        self.assertEqual(images[1]['id'], image_id)

        # 21. GET /images with filter on user-defined property 'distro'.
        # Verify both images are returned
        path = "http://%s:%d/v1/images?property-distro=Ubuntu" % \
               ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 2)
        self.assertEqual(images[0]['id'], image2_id)
        self.assertEqual(images[1]['id'], image_id)

        # 22. GET /images with filter on user-defined property 'distro' but
        # with non-existent value. Verify no images are returned
        path = "http://%s:%d/v1/images?property-distro=fedora" % \
               ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 23. GET /images with filter on non-existent user-defined property
        # 'boo'. Verify no images are returned
        path = "http://%s:%d/v1/images?property-boo=bar" % ("127.0.0.1",
                                                            self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 24. GET /images with filter 'arch=i386'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-arch=i386" % ("127.0.0.1",
                                                              self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image2_id)

        # 25. GET /images with filter 'arch=x86_64'
        # Verify only image1 is returned
        path = "http://%s:%d/v1/images?property-arch=x86_64" % ("127.0.0.1",
                                                                self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image_id)

        # 26. GET /images with filter 'foo=bar'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-foo=bar" % ("127.0.0.1",
                                                            self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image2_id)

        # 27. 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(response.status, 200)

        # 28. Try to list members of deleted image
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 404)

        # 29. Try to update member of deleted image
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        fixture = [{'member_id': 'pattieblack', 'can_share': 'false'}]
        body = jsonutils.dumps(dict(memberships=fixture))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 404)

        # 30. Try to add member to deleted image
        path = ("http://%s:%d/v1/images/%s/members/chickenpattie" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 404)

        # 31. Try to delete member of deleted image
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 404)

        # 32. DELETE image2
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image2_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # 33. GET /images
        # Verify no images are listed
        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)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 34. HEAD /images/detail
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(405, response.status)
        self.assertEqual('GET', response.get('allow'))

        self.stop_servers()
Ejemplo n.º 19
0
    def test_large_objects(self):
        """
        We test the large object manifest code path in the Swift driver.
        In the case where an image file is bigger than the config variable
        swift_store_large_object_size, then we chunk the image into
        Swift, and add a manifest put_object at the end.

        We test that the delete of the large object cleans up all the
        chunks in Swift, in addition to the manifest file (LP Bug# 833285)
        """
        self.cleanup()

        self.swift_store_large_object_size = 2  # In MB
        self.swift_store_large_object_chunk_size = 1  # In MB
        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # POST /images with public image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = "*" * FIVE_MB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_MB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id = data['image']['id']

        # HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")

        # GET image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_MB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_MB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key, expected_value,
                               response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key,
                               expected_value,
                               response[expected_key]))

        self.assertEqual(content, "*" * FIVE_MB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_MB).hexdigest())

        # We test that the delete of the large object cleans up all the
        # chunks in Swift, in addition to the manifest file (LP Bug# 833285)

        # Grab the actual Swift location and query the object manifest for
        # the chunks/segments. We will check that the segments don't exist
        # after we delete the object through Glance...
        path = "http://%s:%d/images/%s" % ("0.0.0.0", self.registry_port,
                                           image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        image_loc = data['image']['location']
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        image_loc = crypt.urlsafe_decrypt(key, image_loc)
        image_loc = get_location_from_uri(image_loc)
        swift_loc = image_loc.store_location

        from swift.common import client as swift_client
        swift_conn = swift_client.Connection(
            authurl=swift_loc.swift_auth_url,
            user=swift_loc.user, key=swift_loc.key)

        # Verify the object manifest exists
        headers = swift_conn.head_object(swift_loc.container, swift_loc.obj)
        manifest = headers.get('x-object-manifest')
        self.assertTrue(manifest is not None, "Manifest could not be found!")

        # Grab the segment identifiers
        obj_container, obj_prefix = manifest.split('/', 1)
        segments = [segment['name'] for segment in
                    swift_conn.get_container(obj_container,
                                             prefix=obj_prefix)[1]]

        # Verify the segments exist
        for segment in segments:
            headers = swift_conn.head_object(obj_container, segment)
            self.assertTrue(headers.get('content-length') is not None,
                            headers)

        # DELETE image
        # Verify image and all chunks are gone...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # Verify the segments no longer exist
        for segment in segments:
            self.assertRaises(swift_client.ClientException,
                              swift_conn.head_object,
                              obj_container, segment)

        self.stop_servers()
Ejemplo n.º 20
0
    def test_remote_image(self):
        """
        Ensure we can retrieve an image that was not stored by glance itself
        """
        self.cleanup()

        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # POST /images with public image named Image1
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.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)

        image_id = data['image']['id']

        # GET image and make sure data was uploaded
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # Find the location that was just added and use it as
        # the remote image location for the next image
        path = "http://%s:%d/images/%s" % ("0.0.0.0", self.registry_port,
                                           image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertTrue('location' in data['image'].keys())
        loc = data['image']['location']
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        swift_location = crypt.urlsafe_decrypt(key, loc)

        # POST /images with public image named Image1 without uploading data
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        headers['X-Image-Meta-Location'] = swift_location
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'], None)
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id2 = data['image']['id']

        # GET /images/2 ensuring the data already in swift is accessible
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id2)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # DELETE boty images
        # Verify image and all chunks are gone...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id2)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 21
0
    def test_cache_middleware_transparent_v1(self):
        """
        We test that putting the cache middleware into the
        application pipeline gives us transparent image caching
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # 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))

        # Grab the 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(response.status, 200)

        # Verify image now in cache
        image_cached_path = os.path.join(self.api_server.image_cache_dir,
                                         image_id)

        # You might wonder why the heck this is here... well, it's here
        # because it took me forever to figure out that the disk write
        # cache in Linux was causing random failures of the os.path.exists
        # assert directly below this. Basically, since the cache is writing
        # the image file to disk in a different process, the write buffers
        # don't flush the cache file during an os.rename() properly, resulting
        # in a false negative on the file existence check below. This little
        # loop pauses the execution of this process for no more than 1.5
        # seconds. If after that time the cached image file still doesn't
        # appear on disk, something really is wrong, and the assert should
        # trigger...
        i = 0
        while not os.path.exists(image_cached_path) and i < 30:
            time.sleep(0.05)
            i = i + 1

        self.assertTrue(os.path.exists(image_cached_path))

        # Now, we delete the image from the server and verify that
        # the image cache no longer contains the deleted 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, 'DELETE')
        self.assertEqual(response.status, 200)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 22
0
    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. POST /images with public image named Image1
        and no custom properties
        - Verify 201 returned
        3. HEAD image
        - Verify HTTP headers have correct information we just added
        4. GET image
        - Verify all information on image we just added is correct
        5. GET /images
        - Verify the image we just added is returned
        6. GET /images/detail
        - Verify the image we just added is returned
        7. PUT image with custom properties of "distro" and "arch"
        - Verify 200 returned
        8. GET image
        - Verify updated information about image was stored
        9. PUT image
        - Remove a previously existing property.
        10. PUT image
        - Add a previously deleted property.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 0. GET /images
        # Verify no public images
        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)
        self.assertEqual(content, '{"images": []}')

        # 1. GET /images/detail
        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 2. 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 = json.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.assertEqual(data['image']['is_public'], True)

        # 3. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              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 image
        # Verify all information on image we just added is correct
        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(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_KB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_KB),
            'content-type': 'application/octet-stream'
        }

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(
                response[expected_key], expected_value,
                "For key '%s' expected header value '%s'. "
                "Got '%s'" %
                (expected_key, expected_value, response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(
                response[expected_key], expected_value,
                "For key '%s' expected header value '%s'. "
                "Got '%s'" %
                (expected_key, expected_value, response[expected_key]))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(
            hashlib.md5(content).hexdigest(),
            hashlib.md5("*" * FIVE_KB).hexdigest())

        # 5. GET /images
        # Verify no public images
        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)

        expected_result = {
            "images": [{
                "container_format": "ovf",
                "disk_format": "raw",
                "id": image_id,
                "name": "Image1",
                "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
                "size": 5120
            }]
        }
        self.assertEqual(json.loads(content), expected_result)

        # 6. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {},
            "size": 5120
        }

        image = json.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value, image['images'][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value,
                              image['images'][0][expected_key]))

        # 7. PUT image with custom properties of "distro" and "arch"
        # Verify 200 returned
        headers = {
            'X-Image-Meta-Property-Distro': 'Ubuntu',
            'X-Image-Meta-Property-Arch': 'x86_64'
        }
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['properties']['arch'], "x86_64")
        self.assertEqual(data['image']['properties']['distro'], "Ubuntu")

        # 8. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {
                'distro': 'Ubuntu',
                'arch': 'x86_64'
            },
            "size": 5120
        }

        image = json.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value, image['images'][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value,
                              image['images'][0][expected_key]))

        # 9. PUT image and remove a previously existing property.
        headers = {'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 1)
        self.assertEqual(data['properties']['arch'], "x86_64")

        # 10. PUT image and add a previously deleted property.
        headers = {
            'X-Image-Meta-Property-Distro': 'Ubuntu',
            'X-Image-Meta-Property-Arch': 'x86_64'
        }
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 2)
        self.assertEqual(data['properties']['arch'], "x86_64")
        self.assertEqual(data['properties']['distro'], "Ubuntu")
        self.assertNotEqual(data['created_at'], data['updated_at'])

        # DELETE 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, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 23
0
    def test_cache_middleware_trans_with_deactivated_image(self):
        """
        Ensure the image v1/v2 API image transfer forbids downloading
        deactivated images.
        Image deactivation is not available in v1. So, we'll deactivate the
        image using v2 but test image transfer with both v1 and v2.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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(201, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # Grab the 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)

        # Verify image in cache
        image_cached_path = os.path.join(self.api_server.image_cache_dir,
                                         image_id)
        self.assertTrue(os.path.exists(image_cached_path))

        # Deactivate the image using v2
        path = "http://%s:%d/v2/images/%s/actions/deactivate"
        path = path % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'POST')
        self.assertEqual(204, response.status)

        # Download the image with v1. Ensure it is forbidden
        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(403, response.status)

        # Download the image with v2. Ensure it is forbidden
        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
                                                   image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(403, response.status)

        # Reactivate the image using v2
        path = "http://%s:%d/v2/images/%s/actions/reactivate"
        path = path % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'POST')
        self.assertEqual(204, response.status)

        # Download the image with v1. Ensure it is allowed
        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)

        # Download the image with v2. Ensure it is allowed
        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
                                                   image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(200, response.status)

        # Now, we delete the image from the server and verify that
        # the image cache no longer contains the deleted 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, 'DELETE')
        self.assertEqual(200, response.status)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 24
0
    def test_large_objects(self):
        """
        We test the large object manifest code path in the Swift driver.
        In the case where an image file is bigger than the config variable
        swift_store_large_object_size, then we chunk the image into
        Swift, and add a manifest put_object at the end.

        We test that the delete of the large object cleans up all the
        chunks in Swift, in addition to the manifest file (LP Bug# 833285)
        """
        self.cleanup()

        self.swift_store_large_object_size = 2  # In MB
        self.swift_store_large_object_chunk_size = 1  # In MB
        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # POST /images with public image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = "*" * FIVE_MB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_MB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id = data['image']['id']

        # HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")

        # GET image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_MB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_MB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key, expected_value,
                               response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key,
                               expected_value,
                               response[expected_key]))

        self.assertEqual(content, "*" * FIVE_MB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_MB).hexdigest())

        # We test that the delete of the large object cleans up all the
        # chunks in Swift, in addition to the manifest file (LP Bug# 833285)

        # Grab the actual Swift location and query the object manifest for
        # the chunks/segments. We will check that the segments don't exist
        # after we delete the object through Glance...
        path = "http://%s:%d/images/%s" % ("0.0.0.0", self.registry_port,
                                           image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        image_loc = data['image']['location']
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        image_loc = crypt.urlsafe_decrypt(key, image_loc)
        image_loc = get_location_from_uri(image_loc)
        swift_loc = image_loc.store_location

        from swift.common import client as swift_client
        swift_conn = swift_client.Connection(
            authurl=swift_loc.swift_auth_url,
            user=swift_loc.user, key=swift_loc.key)

        # Verify the object manifest exists
        headers = swift_conn.head_object(swift_loc.container, swift_loc.obj)
        manifest = headers.get('x-object-manifest')
        self.assertTrue(manifest is not None, "Manifest could not be found!")

        # Grab the segment identifiers
        obj_container, obj_prefix = manifest.split('/', 1)
        segments = [segment['name'] for segment in
                    swift_conn.get_container(obj_container,
                                             prefix=obj_prefix)[1]]

        # Verify the segments exist
        for segment in segments:
            headers = swift_conn.head_object(obj_container, segment)
            self.assertTrue(headers.get('content-length') is not None,
                            headers)

        # DELETE image
        # Verify image and all chunks are gone...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # Verify the segments no longer exist
        for segment in segments:
            self.assertRaises(swift_client.ClientException,
                              swift_conn.head_object,
                              obj_container, segment)

        self.stop_servers()
Ejemplo n.º 25
0
    def test_remote_image(self):
        """
        Ensure we can retrieve an image that was not stored by glance itself
        """
        self.cleanup()

        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # POST /images with public image named Image1
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.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)

        image_id = data['image']['id']

        # GET image and make sure data was uploaded
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # Find the location that was just added and use it as
        # the remote image location for the next image
        path = "http://%s:%d/images/%s" % ("0.0.0.0", self.registry_port,
                                           image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertTrue('location' in data['image'].keys())
        loc = data['image']['location']
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        swift_location = crypt.urlsafe_decrypt(key, loc)

        # POST /images with public image named Image1 without uploading data
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        headers['X-Image-Meta-Location'] = swift_location
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'], None)
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id2 = data['image']['id']

        # GET /images/2 ensuring the data already in swift is accessible
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id2)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # DELETE boty images
        # Verify image and all chunks are gone...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id2)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 26
0
    def test_add_large_object_manifest_uneven_size(self):
        """
        Test when large object manifest in scenario where
        image size % chunk size != 0
        """
        self.cleanup()

        self.swift_store_large_object_size = 3  # In MB
        self.swift_store_large_object_chunk_size = 2  # In MB
        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # 0. GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 1. POST /images with public image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = "*" * FIVE_MB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_MB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id = data['image']['id']

        # 4. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")

        # 5. GET image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_MB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_MB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key, expected_value,
                               response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key,
                               expected_value,
                               response[expected_key]))

        self.assertEqual(content, "*" * FIVE_MB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_MB).hexdigest())

        # DELETE image
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 27
0
    def test_private_images_admin(self):
        """
        Test that admin users can manipulate is_public and owner
        settings on an image.
        """
        self.cleanup()
        self.start_servers()

        # Need to push an image up
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1', public=False)
        headers['X-Auth-Token'] = keystone_utils.pattieblack_token
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201)
        data = json.loads(content)
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], False)
        self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)

        image_id = data['image']['id']

        # Make sure admin does not see image by default
        headers = {'X-Auth-Token': keystone_utils.admin_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Shouldn't show up in the detail list, either
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Admin should see the image if we're looking for private
        # images specifically
        headers = {'X-Auth-Token': keystone_utils.admin_token}
        path = "http://%s:%d/v1/images?is_public=false" % ("0.0.0.0",
                                                           self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")

        # Also in the detail list...
        headers = {'X-Auth-Token': keystone_utils.admin_token}
        path = ("http://%s:%d/v1/images/detail?is_public=false" %
                ("0.0.0.0", self.api_port))
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")
        self.assertEqual(data['images'][0]['is_public'], False)
        self.assertEqual(data['images'][0]['owner'],
                         keystone_utils.pattieblack_id)

        image_id = data['images'][0]['id']

        # Admin should be able to get the image metadata
        headers = {'X-Auth-Token': keystone_utils.admin_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # And of course the image itself
        headers = {'X-Auth-Token': keystone_utils.admin_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # Admin should be able to manipulate is_public
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'],
                         keystone_utils.pattieblack_id)

        # Admin should also be able to change the ownership of the
        # image
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'], 'froggy')

        # Even setting it to no owner
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Owner': ''}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'], None)

        # Make sure pattieblack can see it, since it's unowned but
        # public
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")

        # But if we change it back to private...
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Is-Public': 'False'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], False)
        self.assertEqual(data['image']['owner'], None)

        # Now pattieblack can't see it in the list...
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Or in the details list...
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # But pattieblack should be able to access the image metadata
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertFalse('x-image-meta-owner' in response)

        # And of course the image itself
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertFalse('x-image-meta-owner' in response)

        # Pattieblack can't change is-public, though
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token,
                   'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 404)

        # Or give themselves ownership
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token,
                   'X-Image-Meta-Owner': keystone_utils.pattieblack_id}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 404)

        # They can't delete it, either
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE', headers=headers)
        self.assertEqual(response.status, 404)

        self.stop_servers()
Ejemplo n.º 28
0
    def test_download_non_exists_image_raises_http_not_found(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. HEAD image
        - Verify HTTP headers have correct information we just added
        2. GET image
        - Verify all information on image we just added is correct
        3. DELETE image1
        - Delete the newly added image
        4. GET image
        - Verify that 404 HTTPNotFound exception is raised
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        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(http_client.CREATED, response.status)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        # 1. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual("Image1", response['x-image-meta-name'])

        # 2. GET /images
        # Verify one public image
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(http_client.OK, response.status)

        expected_result = {"images": [
            {"container_format": "ovf",
             "disk_format": "raw",
             "id": image_id,
             "name": "Image1",
             "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
             "size": 5120}]}
        self.assertEqual(expected_result, jsonutils.loads(content))

        # 3. 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(http_client.OK, response.status)

        # 4. GET image
        # Verify that 404 HTTPNotFound exception is raised
        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(http_client.NOT_FOUND, response.status)

        self.stop_servers()
Ejemplo n.º 29
0
    def test_status_cannot_be_manipulated_directly(self):
        self.cleanup()
        self.start_servers(**self.__dict__.copy())
        headers = minimal_headers('Image1')

        # Create a 'queued' image
        http = httplib2.Http()
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Disk-Format': 'raw',
                   'X-Image-Meta-Container-Format': 'bare'}
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'POST', headers=headers,
                                         body=None)
        self.assertEqual(http_client.CREATED, response.status)
        image = jsonutils.loads(content)['image']
        self.assertEqual('queued', image['status'])

        # Ensure status of 'queued' image can't be changed
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image['id'])
        http = httplib2.Http()
        headers = {'X-Image-Meta-Status': 'active'}
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.FORBIDDEN, response.status)
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('queued', response['x-image-meta-status'])

        # We allow 'setting' to the same status
        http = httplib2.Http()
        headers = {'X-Image-Meta-Status': 'queued'}
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.OK, response.status)
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('queued', response['x-image-meta-status'])

        # Make image active
        http = httplib2.Http()
        headers = {'Content-Type': 'application/octet-stream'}
        response, content = http.request(path, 'PUT', headers=headers,
                                         body='data')
        self.assertEqual(http_client.OK, response.status)
        image = jsonutils.loads(content)['image']
        self.assertEqual('active', image['status'])

        # Ensure status of 'active' image can't be changed
        http = httplib2.Http()
        headers = {'X-Image-Meta-Status': 'queued'}
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.FORBIDDEN, response.status)
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('active', response['x-image-meta-status'])

        # We allow 'setting' to the same status
        http = httplib2.Http()
        headers = {'X-Image-Meta-Status': 'active'}
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.OK, response.status)
        response, content = http.request(path, 'HEAD')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('active', response['x-image-meta-status'])

        # Create a 'queued' image, ensure 'status' header is ignored
        http = httplib2.Http()
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Status': 'active'}
        response, content = http.request(path, 'POST', headers=headers,
                                         body=None)
        self.assertEqual(http_client.CREATED, response.status)
        image = jsonutils.loads(content)['image']
        self.assertEqual('queued', image['status'])

        # Create an 'active' image, ensure 'status' header is ignored
        http = httplib2.Http()
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        headers = {'Content-Type': 'application/octet-stream',
                   'X-Image-Meta-Disk-Format': 'raw',
                   'X-Image-Meta-Status': 'queued',
                   'X-Image-Meta-Container-Format': 'bare'}
        response, content = http.request(path, 'POST', headers=headers,
                                         body='data')
        self.assertEqual(http_client.CREATED, response.status)
        image = jsonutils.loads(content)['image']
        self.assertEqual('active', image['status'])
        self.stop_servers()
Ejemplo n.º 30
0
    def _do_test_copy_from(self, from_store, get_uri):
        """
        Ensure we can copy from an external image in from_store.
        """
        self.cleanup()

        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # POST /images with public image to be stored in from_store,
        # to stand in for the 'external' image
        image_data = "*" * FIVE_KB
        headers = minimal_headers('external')
        headers['X-Image-Meta-Store'] = from_store
        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, content)
        data = json.loads(content)

        original_image_id = data['image']['id']

        copy_from = get_uri(self, original_image_id)

        # POST /images with public image copied from_store (to Swift)
        headers = {
            'X-Image-Meta-Name': 'copied',
            'X-Image-Meta-Is-Public': 'True',
            'X-Image-Meta-disk_format': 'raw',
            'X-Image-Meta-container_format': 'ovf',
            'X-Glance-API-Copy-From': copy_from
        }
        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, content)
        data = json.loads(content)

        copy_image_id = data['image']['id']
        self.assertNotEqual(copy_image_id, original_image_id)

        # GET image and make sure image content is as expected
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(
            hashlib.md5(content).hexdigest(),
            hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "copied")

        # DELETE original image
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              original_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # GET image again to make sure the existence of the original
        # image in from_store is not depended on
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(
            hashlib.md5(content).hexdigest(),
            hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "copied")

        # DELETE copied image
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 31
0
    def test_add_large_object_manifest_uneven_size(self):
        """
        Test when large object manifest in scenario where
        image size % chunk size != 0
        """
        self.cleanup()

        self.swift_store_large_object_size = 3  # In MB
        self.swift_store_large_object_chunk_size = 2  # In MB
        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # 0. GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 1. POST /images with public image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = "*" * FIVE_MB
        headers = minimal_headers("Image1")
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "POST", headers=headers, body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data["image"]["checksum"], hashlib.md5(image_data).hexdigest())
        self.assertEqual(data["image"]["size"], FIVE_MB)
        self.assertEqual(data["image"]["name"], "Image1")
        self.assertEqual(data["image"]["is_public"], True)

        image_id = data["image"]["id"]

        # 4. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "HEAD")
        self.assertEqual(response.status, 200)
        self.assertEqual(response["x-image-meta-name"], "Image1")

        # 5. GET image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(response.status, 200)

        expected_image_headers = {
            "x-image-meta-id": image_id,
            "x-image-meta-name": "Image1",
            "x-image-meta-is_public": "True",
            "x-image-meta-status": "active",
            "x-image-meta-disk_format": "raw",
            "x-image-meta-container_format": "ovf",
            "x-image-meta-size": str(FIVE_MB),
        }

        expected_std_headers = {"content-length": str(FIVE_MB), "content-type": "application/octet-stream"}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(
                response[expected_key],
                expected_value,
                "For key '%s' expected header value '%s'. Got '%s'"
                % (expected_key, expected_value, response[expected_key]),
            )

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(
                response[expected_key],
                expected_value,
                "For key '%s' expected header value '%s'. Got '%s'"
                % (expected_key, expected_value, response[expected_key]),
            )

        self.assertEqual(content, "*" * FIVE_MB)
        self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_MB).hexdigest())

        # DELETE image
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 32
0
    def test_cache_middleware_trans_with_deactivated_image(self):
        """
        Ensure the image v1/v2 API image transfer forbids downloading
        deactivated images.
        Image deactivation is not available in v1. So, we'll deactivate the
        image using v2 but test image transfer with both v1 and v2.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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(201, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(
            hashlib.md5(image_data).hexdigest(), data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # Grab the 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)

        # Verify image in cache
        image_cached_path = os.path.join(self.api_server.image_cache_dir,
                                         image_id)
        self.assertTrue(os.path.exists(image_cached_path))

        # Deactivate the image using v2
        path = "http://%s:%d/v2/images/%s/actions/deactivate"
        path = path % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'POST')
        self.assertEqual(204, response.status)

        # Download the image with v1. Ensure it is forbidden
        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(403, response.status)

        # Download the image with v2. Ensure it is forbidden
        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
                                                   image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(403, response.status)

        # Reactivate the image using v2
        path = "http://%s:%d/v2/images/%s/actions/reactivate"
        path = path % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'POST')
        self.assertEqual(204, response.status)

        # Download the image with v1. Ensure it is allowed
        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)

        # Download the image with v2. Ensure it is allowed
        path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
                                                   image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(200, response.status)

        # Now, we delete the image from the server and verify that
        # the image cache no longer contains the deleted 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, 'DELETE')
        self.assertEqual(200, response.status)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 33
0
    def test_updating_is_public(self):
        """Verify that we can update the is_public attribute."""
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Verify no public images
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('{"images": []}', content.decode())

        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(http_client.OK, response.status)
        self.assertEqual('{"images": []}', content.decode())

        # POST /images with private image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = b"*" * FIVE_KB
        headers = minimal_headers('Image1', public=False)
        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(http_client.CREATED, response.status)
        data = jsonutils.loads(content)
        image_id = data['image']['id']
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertFalse(data['image']['is_public'])

        # Retrieve image again to verify it was created appropriately
        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(http_client.OK, response.status)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'False',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_KB)}

        expected_std_headers = {
            'content-length': str(FIVE_KB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(expected_value, response[expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(expected_value, response[expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        self.assertEqual(image_data, content)
        self.assertEqual(hashlib.md5(image_data).hexdigest(),
                         hashlib.md5(content).hexdigest())

        # PUT image with custom properties to make public and then
        # Verify 200 returned
        headers = {'X-Image-Meta-is_public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.OK, response.status)
        image = jsonutils.loads(content)
        is_public = image['image']['is_public']
        self.assertTrue(
            is_public,
            "Expected image to be public but received %s" % is_public)

        # PUT image with custom properties to make private and then
        # Verify 200 returned
        headers = {'X-Image-Meta-is_public': 'False'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(http_client.OK, response.status)
        image = jsonutils.loads(content)
        is_public = image['image']['is_public']
        self.assertFalse(
            is_public,
            "Expected image to be private but received %s" % is_public)
Ejemplo n.º 34
0
    def _do_test_copy_from(self, from_store, get_uri):
        """
        Ensure we can copy from an external image in from_store.
        """
        self.cleanup()

        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # POST /images with public image to be stored in from_store,
        # to stand in for the 'external' image
        image_data = "*" * FIVE_KB
        headers = minimal_headers("external")
        headers["X-Image-Meta-Store"] = from_store
        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, content)
        data = json.loads(content)

        original_image_id = data["image"]["id"]

        copy_from = get_uri(self, original_image_id)

        # POST /images with public image copied from_store (to Swift)
        headers = {
            "X-Image-Meta-Name": "copied",
            "X-Image-Meta-Is-Public": "True",
            "X-Image-Meta-disk_format": "raw",
            "X-Image-Meta-container_format": "ovf",
            "X-Glance-API-Copy-From": copy_from,
        }
        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, content)
        data = json.loads(content)

        copy_image_id = data["image"]["id"]
        self.assertNotEqual(copy_image_id, original_image_id)

        # GET image and make sure image content is as expected
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(response.status, 200)
        self.assertEqual(response["content-length"], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data["image"]["size"], FIVE_KB)
        self.assertEqual(data["image"]["name"], "copied")

        # DELETE original image
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, original_image_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(response.status, 200)

        # GET image again to make sure the existence of the original
        # image in from_store is not depended on
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(response.status, 200)
        self.assertEqual(response["content-length"], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(), hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data["image"]["size"], FIVE_KB)
        self.assertEqual(data["image"]["name"], "copied")

        # DELETE copied image
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 35
0
    def test_add_large_object_manifest_uneven_size(self):
        """
        Test when large object manifest in scenario where
        image size % chunk size != 0
        """
        self.cleanup()

        self.swift_store_large_object_size = 3  # In MB
        self.swift_store_large_object_chunk_size = 2  # In MB
        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # 0. GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 1. POST /images with public image named Image1
        # attribute and no custom properties. Verify a 200 OK is returned
        image_data = "*" * FIVE_MB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_MB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)

        image_id = data['image']['id']

        # 4. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")

        # 5. GET image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_MB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_MB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key, expected_value,
                               response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                            "For key '%s' expected header value '%s'. Got '%s'"
                            % (expected_key,
                               expected_value,
                               response[expected_key]))

        self.assertEqual(content, "*" * FIVE_MB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_MB).hexdigest())

        # DELETE image
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 36
0
    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. POST /images with public image named Image1
        and no custom properties
        - Verify 201 returned
        3. HEAD image
        - Verify HTTP headers have correct information we just added
        4. GET image
        - Verify all information on image we just added is correct
        5. GET /images
        - Verify the image we just added is returned
        6. GET /images/detail
        - Verify the image we just added is returned
        7. PUT image with custom properties of "distro" and "arch"
        - Verify 200 returned
        8. PUT image with too many custom properties
        - Verify 413 returned
        9. GET image
        - Verify updated information about image was stored
        10. PUT image
        - Remove a previously existing property.
        11. PUT image
        - Add a previously deleted property.
        12. PUT image/members/member1
        - Add member1 to image
        13. PUT image/members/member2
        - Add member2 to image
        14. GET image/members
        - List image members
        15. DELETE image/members/member1
        - Delete image member1
        16. PUT image/members
        - Attempt to replace members with an overlimit amount
        17. PUT image/members/member11
        - Attempt to add a member while at limit
        18. POST /images with another public image named Image2
        - attribute and three custom properties, "distro", "arch" & "foo"
        - Verify a 200 OK is returned
        19. HEAD image2
        - Verify image2 found now
        20. GET /images
        - Verify 2 public images
        21. GET /images with filter on user-defined property "distro".
        - Verify both images are returned
        22. GET /images with filter on user-defined property 'distro' but
        - with non-existent value. Verify no images are returned
        23. GET /images with filter on non-existent user-defined property
        - "boo". Verify no images are returned
        24. GET /images with filter 'arch=i386'
        - Verify only image2 is returned
        25. GET /images with filter 'arch=x86_64'
        - Verify only image1 is returned
        26. GET /images with filter 'foo=bar'
        - Verify only image2 is returned
        27. DELETE image1
        - Delete image
        28. GET image/members
        -  List deleted image members
        29. PUT image/members/member2
        - Update existing member2 of deleted image
        30. PUT image/members/member3
        - Add member3 to deleted image
        31. DELETE image/members/member2
        - Delete member2 from deleted image
        32. DELETE image2
        - Delete image
        33. GET /images
        - Verify no images are listed
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 0. GET /images
        # Verify no public images
        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)
        self.assertEqual(content, '{"images": []}')

        # 1. GET /images/detail
        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 2. 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)
        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.assertEqual(data['image']['is_public'], True)

        # 3. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              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 image
        # Verify all information on image we just added is correct
        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(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_KB)
        }

        expected_std_headers = {
            'content-length': str(FIVE_KB),
            'content-type': 'application/octet-stream'
        }

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(
                response[expected_key], expected_value,
                "For key '%s' expected header value '%s'. "
                "Got '%s'" %
                (expected_key, expected_value, response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(
                response[expected_key], expected_value,
                "For key '%s' expected header value '%s'. "
                "Got '%s'" %
                (expected_key, expected_value, response[expected_key]))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(
            hashlib.md5(content).hexdigest(),
            hashlib.md5("*" * FIVE_KB).hexdigest())

        # 5. GET /images
        # Verify one public image
        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)

        expected_result = {
            "images": [{
                "container_format": "ovf",
                "disk_format": "raw",
                "id": image_id,
                "name": "Image1",
                "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
                "size": 5120
            }]
        }
        self.assertEqual(jsonutils.loads(content), expected_result)

        # 6. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {},
            "size": 5120
        }

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value, image['images'][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value,
                              image['images'][0][expected_key]))

        # 7. PUT image with custom properties of "distro" and "arch"
        # Verify 200 returned
        headers = {
            'X-Image-Meta-Property-Distro': 'Ubuntu',
            'X-Image-Meta-Property-Arch': 'x86_64'
        }
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(data['image']['properties']['arch'], "x86_64")
        self.assertEqual(data['image']['properties']['distro'], "Ubuntu")

        # 8. PUT image with too many custom properties
        # Verify 413 returned
        headers = {}
        for i in range(11):  # configured limit is 10
            headers['X-Image-Meta-Property-foo%d' % i] = 'bar'
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 413)

        # 9. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {
                'distro': 'Ubuntu',
                'arch': 'x86_64'
            },
            "size": 5120
        }

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value, image['images'][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value,
                              image['images'][0][expected_key]))

        # 10. PUT image and remove a previously existing property.
        headers = {'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 1)
        self.assertEqual(data['properties']['arch'], "x86_64")

        # 11. PUT image and add a previously deleted property.
        headers = {
            'X-Image-Meta-Property-Distro': 'Ubuntu',
            'X-Image-Meta-Property-Arch': 'x86_64'
        }
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 2)
        self.assertEqual(data['properties']['arch'], "x86_64")
        self.assertEqual(data['properties']['distro'], "Ubuntu")
        self.assertNotEqual(data['created_at'], data['updated_at'])

        # 12. Add member to image
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 204)

        # 13. Add member to image
        path = ("http://%s:%d/v1/images/%s/members/pattiewhite" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 204)

        # 14. List image members
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = jsonutils.loads(content)
        self.assertEqual(len(data['members']), 2)
        self.assertEqual(data['members'][0]['member_id'], 'pattieblack')
        self.assertEqual(data['members'][1]['member_id'], 'pattiewhite')

        # 15. Delete image member
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 204)

        # 16. Attempt to replace members with an overlimit amount
        # Adding 11 image members should fail since configured limit is 10
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        memberships = []
        for i in range(11):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 413)

        # 17. Attempt to add a member while at limit
        # Adding an 11th member should fail since configured limit is 10
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        memberships = []
        for i in range(10):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 204)

        path = ("http://%s:%d/v1/images/%s/members/fail_me" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 413)

        # 18. POST /images with another public image named Image2
        # attribute and three custom properties, "distro", "arch" & "foo".
        # Verify a 200 OK is returned
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image2')
        headers['X-Image-Meta-Property-Distro'] = 'Ubuntu'
        headers['X-Image-Meta-Property-Arch'] = 'i386'
        headers['X-Image-Meta-Property-foo'] = 'bar'
        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)
        image2_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'], "Image2")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['properties']['distro'], 'Ubuntu')
        self.assertEqual(data['image']['properties']['arch'], 'i386')
        self.assertEqual(data['image']['properties']['foo'], 'bar')

        # 19. HEAD image2
        # Verify image2 found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image2_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image2")

        # 20. GET /images
        # Verify 2 public images
        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)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 2)
        self.assertEqual(images[0]['id'], image2_id)
        self.assertEqual(images[1]['id'], image_id)

        # 21. GET /images with filter on user-defined property 'distro'.
        # Verify both images are returned
        path = "http://%s:%d/v1/images?property-distro=Ubuntu" % \
               ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 2)
        self.assertEqual(images[0]['id'], image2_id)
        self.assertEqual(images[1]['id'], image_id)

        # 22. GET /images with filter on user-defined property 'distro' but
        # with non-existent value. Verify no images are returned
        path = "http://%s:%d/v1/images?property-distro=fedora" % \
               ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 23. GET /images with filter on non-existent user-defined property
        # 'boo'. Verify no images are returned
        path = "http://%s:%d/v1/images?property-boo=bar" % ("127.0.0.1",
                                                            self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 24. GET /images with filter 'arch=i386'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-arch=i386" % ("127.0.0.1",
                                                              self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image2_id)

        # 25. GET /images with filter 'arch=x86_64'
        # Verify only image1 is returned
        path = "http://%s:%d/v1/images?property-arch=x86_64" % ("127.0.0.1",
                                                                self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image_id)

        # 26. GET /images with filter 'foo=bar'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-foo=bar" % ("127.0.0.1",
                                                            self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 1)
        self.assertEqual(images[0]['id'], image2_id)

        # 27. 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(response.status, 200)

        # 28. Try to list members of deleted image
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 404)

        # 29. Try to update member of deleted image
        path = ("http://%s:%d/v1/images/%s/members" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        fixture = [{'member_id': 'pattieblack', 'can_share': 'false'}]
        body = jsonutils.dumps(dict(memberships=fixture))
        response, content = http.request(path, 'PUT', body=body)
        self.assertEqual(response.status, 404)

        # 30. Try to add member to deleted image
        path = ("http://%s:%d/v1/images/%s/members/chickenpattie" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'PUT')
        self.assertEqual(response.status, 404)

        # 31. Try to delete member of deleted image
        path = ("http://%s:%d/v1/images/%s/members/pattieblack" %
                ("127.0.0.1", self.api_port, image_id))
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 404)

        # 32. DELETE image2
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image2_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # 33. GET /images
        # Verify no images are listed
        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)
        images = jsonutils.loads(content)['images']
        self.assertEqual(len(images), 0)

        # 34. HEAD /images/detail
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(405, response.status)
        self.assertEqual('GET', response.get('allow'))

        self.stop_servers()
Ejemplo n.º 37
0
    def _do_test_copy_from(self, from_store, get_uri):
        """
        Ensure we can copy from an external image in from_store.
        """
        self.cleanup()

        self.start_servers(**self.__dict__.copy())

        api_port = self.api_port
        registry_port = self.registry_port

        # POST /images with public image to be stored in from_store,
        # to stand in for the 'external' image
        image_data = "*" * FIVE_KB
        headers = minimal_headers('external')
        headers['X-Image-Meta-Store'] = from_store
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)

        original_image_id = data['image']['id']

        copy_from = get_uri(self, original_image_id)

        # POST /images with public image copied from_store (to Swift)
        headers = {'X-Image-Meta-Name': 'copied',
                   'X-Image-Meta-disk_format': 'raw',
                   'X-Image-Meta-container_format': 'ovf',
                   'X-Image-Meta-Is-Public': 'True',
                   'X-Glance-API-Copy-From': copy_from}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201, content)
        data = json.loads(content)

        copy_image_id = data['image']['id']

        # GET image and make sure image content is as expected
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "copied")

        # DELETE original image
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              original_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        # GET image again to make sure the existence of the original
        # image in from_store is not depended on
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "copied")

        # DELETE copied image
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              copy_image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 38
0
    def test_download_non_exists_image_raises_http_not_found(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. HEAD image
        - Verify HTTP headers have correct information we just added
        2. GET image
        - Verify all information on image we just added is correct
        3. DELETE image1
        - Delete the newly added image
        4. GET image
        - Verify that 404 HTTPNotFound exception is raised
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        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(201, response.status)
        data = jsonutils.loads(content)
        image_id = data["image"]["id"]
        self.assertEqual(hashlib.md5(image_data).hexdigest(), data["image"]["checksum"])
        self.assertEqual(FIVE_KB, data["image"]["size"])
        self.assertEqual("Image1", data["image"]["name"])
        self.assertTrue(data["image"]["is_public"])

        # 1. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("Image1", response["x-image-meta-name"])

        # 2. GET /images
        # Verify one public image
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)

        expected_result = {
            "images": [
                {
                    "container_format": "ovf",
                    "disk_format": "raw",
                    "id": image_id,
                    "name": "Image1",
                    "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
                    "size": 5120,
                }
            ]
        }
        self.assertEqual(expected_result, jsonutils.loads(content))

        # 3. 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)

        # 4. GET image
        # Verify that 404 HTTPNotFound exception is raised
        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(404, response.status)

        self.stop_servers()
Ejemplo n.º 39
0
    def test_private_images_anon(self):
        """
        Test that anonymous users can access images but not manipulate
        them.
        """
        self.cleanup()
        self.start_servers()

        # Make sure anonymous user can't push up an image
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1', public=False)
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 403)

        # Now push up an image for anonymous user to try to access
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1', public=False)
        headers['X-Auth-Token'] = keystone_utils.pattieblack_token
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201)
        data = json.loads(content)
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], False)
        self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)

        image_id = data['image']['id']

        # Make sure anonymous user can't list the image
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Shouldn't show up in the detail list, either
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Also check that anonymous can't get the image metadata
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 404)

        # Nor the image, either.
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 404)

        # Anonymous shouldn't be able to make the image public...
        headers = {'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Nor change ownership...
        headers = {'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Nor even delete it...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 403)

        # Now, let's use our admin credentials and change the
        # ownership to None...
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Owner': ''}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], False)
        self.assertEqual(data['image']['owner'], None)

        # Anonymous user still can't list image...
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Nor see it in details...
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # But they should be able to access the metadata...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertFalse('x-image-meta-owner' in response)

        # And even the image itself...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertFalse('x-image-meta-owner' in response)

        # Anonymous still shouldn't be able to make the image
        # public...
        headers = {'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Nor change ownership...
        headers = {'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Nor even delete it...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 403)

        # Now make the image public...
        headers = {'X-Auth-Token': keystone_utils.admin_token,
                   'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'], None)

        # Now the user should see it in the list...
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")

        # Especially in the details...
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")
        self.assertEqual(data['images'][0]['is_public'], True)
        self.assertEqual(data['images'][0]['owner'], None)

        # But still can't change ownership...
        headers = {'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Or delete it...
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE')
        self.assertEqual(response.status, 403)

        self.stop_servers()
Ejemplo n.º 40
0
    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. POST /images with public image named Image1
        and no custom properties
        - Verify 201 returned
        3. HEAD image
        - Verify HTTP headers have correct information we just added
        4. GET image
        - Verify all information on image we just added is correct
        5. GET /images
        - Verify the image we just added is returned
        6. GET /images/detail
        - Verify the image we just added is returned
        7. PUT image with custom properties of "distro" and "arch"
        - Verify 200 returned
        8. GET image
        - Verify updated information about image was stored
        9. PUT image
        - Remove a previously existing property.
        10. PUT image
        - Add a previously deleted property.
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 0. GET /images
        # Verify no public images
        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)
        self.assertEqual(content, '{"images": []}')

        # 1. GET /images/detail
        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # 2. 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 = json.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.assertEqual(data['image']['is_public'], True)

        # 3. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              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 image
        # Verify all information on image we just added is correct
        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(response.status, 200)

        expected_image_headers = {
            'x-image-meta-id': image_id,
            'x-image-meta-name': 'Image1',
            'x-image-meta-is_public': 'True',
            'x-image-meta-status': 'active',
            'x-image-meta-disk_format': 'raw',
            'x-image-meta-container_format': 'ovf',
            'x-image-meta-size': str(FIVE_KB)}

        expected_std_headers = {
            'content-length': str(FIVE_KB),
            'content-type': 'application/octet-stream'}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(response[expected_key], expected_value,
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           response[expected_key]))

        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(hashlib.md5(content).hexdigest(),
                         hashlib.md5("*" * FIVE_KB).hexdigest())

        # 5. GET /images
        # Verify no public images
        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)

        expected_result = {"images": [
            {"container_format": "ovf",
             "disk_format": "raw",
             "id": image_id,
             "name": "Image1",
             "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
             "size": 5120}]}
        self.assertEqual(json.loads(content), expected_result)

        # 6. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {},
            "size": 5120}

        image = json.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(expected_value, image['images'][0][expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           image['images'][0][expected_key]))

        # 7. PUT image with custom properties of "distro" and "arch"
        # Verify 200 returned
        headers = {'X-Image-Meta-Property-Distro': 'Ubuntu',
                   'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['properties']['arch'], "x86_64")
        self.assertEqual(data['image']['properties']['distro'], "Ubuntu")

        # 8. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {'distro': 'Ubuntu', 'arch': 'x86_64'},
            "size": 5120}

        image = json.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(expected_value, image['images'][0][expected_key],
                             "For key '%s' expected header value '%s'. "
                             "Got '%s'" % (expected_key,
                                           expected_value,
                                           image['images'][0][expected_key]))

        # 9. PUT image and remove a previously existing property.
        headers = {'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 1)
        self.assertEqual(data['properties']['arch'], "x86_64")

        # 10. PUT image and add a previously deleted property.
        headers = {'X-Image-Meta-Property-Distro': 'Ubuntu',
                   'X-Image-Meta-Property-Arch': 'x86_64'}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, 'GET')
        self.assertEqual(response.status, 200)
        data = json.loads(content)['images'][0]
        self.assertEqual(len(data['properties']), 2)
        self.assertEqual(data['properties']['arch'], "x86_64")
        self.assertEqual(data['properties']['distro'], "Ubuntu")
        self.assertNotEqual(data['created_at'], data['updated_at'])

        # DELETE 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, 'DELETE')
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 41
0
    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. POST /images with public image named Image1
        and no custom properties
        - Verify 201 returned
        3. HEAD image
        - Verify HTTP headers have correct information we just added
        4. GET image
        - Verify all information on image we just added is correct
        5. GET /images
        - Verify the image we just added is returned
        6. GET /images/detail
        - Verify the image we just added is returned
        7. PUT image with custom properties of "distro" and "arch"
        - Verify 200 returned
        8. PUT image with too many custom properties
        - Verify 413 returned
        9. GET image
        - Verify updated information about image was stored
        10. PUT image
        - Remove a previously existing property.
        11. PUT image
        - Add a previously deleted property.
        12. PUT image/members/member1
        - Add member1 to image
        13. PUT image/members/member2
        - Add member2 to image
        14. GET image/members
        - List image members
        15. DELETE image/members/member1
        - Delete image member1
        16. PUT image/members
        - Attempt to replace members with an overlimit amount
        17. PUT image/members/member11
        - Attempt to add a member while at limit
        18. POST /images with another public image named Image2
        - attribute and three custom properties, "distro", "arch" & "foo"
        - Verify a 200 OK is returned
        19. HEAD image2
        - Verify image2 found now
        20. GET /images
        - Verify 2 public images
        21. GET /images with filter on user-defined property "distro".
        - Verify both images are returned
        22. GET /images with filter on user-defined property 'distro' but
        - with non-existent value. Verify no images are returned
        23. GET /images with filter on non-existent user-defined property
        - "boo". Verify no images are returned
        24. GET /images with filter 'arch=i386'
        - Verify only image2 is returned
        25. GET /images with filter 'arch=x86_64'
        - Verify only image1 is returned
        26. GET /images with filter 'foo=bar'
        - Verify only image2 is returned
        27. DELETE image1
        - Delete image
        28. GET image/members
        -  List deleted image members
        29. PUT image/members/member2
        - Update existing member2 of deleted image
        30. PUT image/members/member3
        - Add member3 to deleted image
        31. DELETE image/members/member2
        - Delete member2 from deleted image
        32. DELETE image2
        - Delete image
        33. GET /images
        - Verify no images are listed
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 0. GET /images
        # Verify no public images
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        self.assertEqual('{"images": []}', content)

        # 1. GET /images/detail
        # Verify no public images
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        self.assertEqual('{"images": []}', content)

        # 2. 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(201, response.status)
        data = jsonutils.loads(content)
        image_id = data["image"]["id"]
        self.assertEqual(hashlib.md5(image_data).hexdigest(), data["image"]["checksum"])
        self.assertEqual(FIVE_KB, data["image"]["size"])
        self.assertEqual("Image1", data["image"]["name"])
        self.assertTrue(data["image"]["is_public"])

        # 3. HEAD image
        # Verify image found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("Image1", response["x-image-meta-name"])

        # 4. GET image
        # Verify all information on image we just added is correct
        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)

        expected_image_headers = {
            "x-image-meta-id": image_id,
            "x-image-meta-name": "Image1",
            "x-image-meta-is_public": "True",
            "x-image-meta-status": "active",
            "x-image-meta-disk_format": "raw",
            "x-image-meta-container_format": "ovf",
            "x-image-meta-size": str(FIVE_KB),
        }

        expected_std_headers = {"content-length": str(FIVE_KB), "content-type": "application/octet-stream"}

        for expected_key, expected_value in expected_image_headers.items():
            self.assertEqual(
                expected_value,
                response[expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value, response[expected_key]),
            )

        for expected_key, expected_value in expected_std_headers.items():
            self.assertEqual(
                expected_value,
                response[expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value, response[expected_key]),
            )

        self.assertEqual("*" * FIVE_KB, content)
        self.assertEqual(hashlib.md5("*" * FIVE_KB).hexdigest(), hashlib.md5(content).hexdigest())

        # 5. GET /images
        # Verify one public image
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)

        expected_result = {
            "images": [
                {
                    "container_format": "ovf",
                    "disk_format": "raw",
                    "id": image_id,
                    "name": "Image1",
                    "checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
                    "size": 5120,
                }
            ]
        }
        self.assertEqual(expected_result, jsonutils.loads(content))

        # 6. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {},
            "size": 5120,
        }

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value,
                image["images"][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value, image["images"][0][expected_key]),
            )

        # 7. PUT image with custom properties of "distro" and "arch"
        # Verify 200 returned
        headers = {"X-Image-Meta-Property-Distro": "Ubuntu", "X-Image-Meta-Property-Arch": "x86_64"}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(200, response.status)
        data = jsonutils.loads(content)
        self.assertEqual("x86_64", data["image"]["properties"]["arch"])
        self.assertEqual("Ubuntu", data["image"]["properties"]["distro"])

        # 8. PUT image with too many custom properties
        # Verify 413 returned
        headers = {}
        for i in range(11):  # configured limit is 10
            headers["X-Image-Meta-Property-foo%d" % i] = "bar"
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(413, response.status)

        # 9. GET /images/detail
        # Verify image and all its metadata
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)

        expected_image = {
            "status": "active",
            "name": "Image1",
            "deleted": False,
            "container_format": "ovf",
            "disk_format": "raw",
            "id": image_id,
            "is_public": True,
            "deleted_at": None,
            "properties": {"distro": "Ubuntu", "arch": "x86_64"},
            "size": 5120,
        }

        image = jsonutils.loads(content)

        for expected_key, expected_value in expected_image.items():
            self.assertEqual(
                expected_value,
                image["images"][0][expected_key],
                "For key '%s' expected header value '%s'. "
                "Got '%s'" % (expected_key, expected_value, image["images"][0][expected_key]),
            )

        # 10. PUT image and remove a previously existing property.
        headers = {"X-Image-Meta-Property-Arch": "x86_64"}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(200, response.status)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        data = jsonutils.loads(content)["images"][0]
        self.assertEqual(1, len(data["properties"]))
        self.assertEqual("x86_64", data["properties"]["arch"])

        # 11. PUT image and add a previously deleted property.
        headers = {"X-Image-Meta-Property-Distro": "Ubuntu", "X-Image-Meta-Property-Arch": "x86_64"}
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(200, response.status)
        data = jsonutils.loads(content)

        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        data = jsonutils.loads(content)["images"][0]
        self.assertEqual(2, len(data["properties"]))
        self.assertEqual("x86_64", data["properties"]["arch"])
        self.assertEqual("Ubuntu", data["properties"]["distro"])
        self.assertNotEqual(data["created_at"], data["updated_at"])

        # 12. Add member to image
        path = "http://%s:%d/v1/images/%s/members/pattieblack" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT")
        self.assertEqual(204, response.status)

        # 13. Add member to image
        path = "http://%s:%d/v1/images/%s/members/pattiewhite" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT")
        self.assertEqual(204, response.status)

        # 14. List image members
        path = "http://%s:%d/v1/images/%s/members" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(2, len(data["members"]))
        self.assertEqual("pattieblack", data["members"][0]["member_id"])
        self.assertEqual("pattiewhite", data["members"][1]["member_id"])

        # 15. Delete image member
        path = "http://%s:%d/v1/images/%s/members/pattieblack" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(204, response.status)

        # 16. Attempt to replace members with an overlimit amount
        # Adding 11 image members should fail since configured limit is 10
        path = "http://%s:%d/v1/images/%s/members" % ("127.0.0.1", self.api_port, image_id)
        memberships = []
        for i in range(11):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, "PUT", body=body)
        self.assertEqual(413, response.status)

        # 17. Attempt to add a member while at limit
        # Adding an 11th member should fail since configured limit is 10
        path = "http://%s:%d/v1/images/%s/members" % ("127.0.0.1", self.api_port, image_id)
        memberships = []
        for i in range(10):
            member_id = "foo%d" % i
            memberships.append(dict(member_id=member_id))
        http = httplib2.Http()
        body = jsonutils.dumps(dict(memberships=memberships))
        response, content = http.request(path, "PUT", body=body)
        self.assertEqual(204, response.status)

        path = "http://%s:%d/v1/images/%s/members/fail_me" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT")
        self.assertEqual(413, response.status)

        # 18. POST /images with another public image named Image2
        # attribute and three custom properties, "distro", "arch" & "foo".
        # Verify a 200 OK is returned
        image_data = "*" * FIVE_KB
        headers = minimal_headers("Image2")
        headers["X-Image-Meta-Property-Distro"] = "Ubuntu"
        headers["X-Image-Meta-Property-Arch"] = "i386"
        headers["X-Image-Meta-Property-foo"] = "bar"
        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)
        image2_id = data["image"]["id"]
        self.assertEqual(hashlib.md5(image_data).hexdigest(), data["image"]["checksum"])
        self.assertEqual(FIVE_KB, data["image"]["size"])
        self.assertEqual("Image2", data["image"]["name"])
        self.assertTrue(data["image"]["is_public"])
        self.assertEqual("Ubuntu", data["image"]["properties"]["distro"])
        self.assertEqual("i386", data["image"]["properties"]["arch"])
        self.assertEqual("bar", data["image"]["properties"]["foo"])

        # 19. HEAD image2
        # Verify image2 found now
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image2_id)
        http = httplib2.Http()
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("Image2", response["x-image-meta-name"])

        # 20. GET /images
        # Verify 2 public images
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(2, len(images))
        self.assertEqual(image2_id, images[0]["id"])
        self.assertEqual(image_id, images[1]["id"])

        # 21. GET /images with filter on user-defined property 'distro'.
        # Verify both images are returned
        path = "http://%s:%d/v1/images?property-distro=Ubuntu" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(2, len(images))
        self.assertEqual(image2_id, images[0]["id"])
        self.assertEqual(image_id, images[1]["id"])

        # 22. GET /images with filter on user-defined property 'distro' but
        # with non-existent value. Verify no images are returned
        path = "http://%s:%d/v1/images?property-distro=fedora" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(0, len(images))

        # 23. GET /images with filter on non-existent user-defined property
        # 'boo'. Verify no images are returned
        path = "http://%s:%d/v1/images?property-boo=bar" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(0, len(images))

        # 24. GET /images with filter 'arch=i386'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-arch=i386" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(1, len(images))
        self.assertEqual(image2_id, images[0]["id"])

        # 25. GET /images with filter 'arch=x86_64'
        # Verify only image1 is returned
        path = "http://%s:%d/v1/images?property-arch=x86_64" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(1, len(images))
        self.assertEqual(image_id, images[0]["id"])

        # 26. GET /images with filter 'foo=bar'
        # Verify only image2 is returned
        path = "http://%s:%d/v1/images?property-foo=bar" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(1, len(images))
        self.assertEqual(image2_id, images[0]["id"])

        # 27. 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)

        # 28. Try to list members of deleted image
        path = "http://%s:%d/v1/images/%s/members" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(404, response.status)

        # 29. Try to update member of deleted image
        path = "http://%s:%d/v1/images/%s/members" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        fixture = [{"member_id": "pattieblack", "can_share": "false"}]
        body = jsonutils.dumps(dict(memberships=fixture))
        response, content = http.request(path, "PUT", body=body)
        self.assertEqual(404, response.status)

        # 30. Try to add member to deleted image
        path = "http://%s:%d/v1/images/%s/members/chickenpattie" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "PUT")
        self.assertEqual(404, response.status)

        # 31. Try to delete member of deleted image
        path = "http://%s:%d/v1/images/%s/members/pattieblack" % ("127.0.0.1", self.api_port, image_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(404, response.status)

        # 32. DELETE image2
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image2_id)
        http = httplib2.Http()
        response, content = http.request(path, "DELETE")
        self.assertEqual(200, response.status)

        # 33. GET /images
        # Verify no images are listed
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "GET")
        self.assertEqual(200, response.status)
        images = jsonutils.loads(content)["images"]
        self.assertEqual(0, len(images))

        # 34. HEAD /images/detail
        path = "http://%s:%d/v1/images/detail" % ("127.0.0.1", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, "HEAD")
        self.assertEqual(405, response.status)
        self.assertEqual("GET", response.get("allow"))

        self.stop_servers()
Ejemplo n.º 42
0
    def test_status_cannot_be_manipulated_directly(self):
        self.cleanup()
        self.start_servers(**self.__dict__.copy())
        headers = minimal_headers("Image1")

        # Create a 'queued' image
        http = httplib2.Http()
        headers = {
            "Content-Type": "application/octet-stream",
            "X-Image-Meta-Disk-Format": "raw",
            "X-Image-Meta-Container-Format": "bare",
        }
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        response, content = http.request(path, "POST", headers=headers, body=None)
        self.assertEqual(201, response.status)
        image = jsonutils.loads(content)["image"]
        self.assertEqual("queued", image["status"])

        # Ensure status of 'queued' image can't be changed
        path = "http://%s:%d/v1/images/%s" % ("127.0.0.1", self.api_port, image["id"])
        http = httplib2.Http()
        headers = {"X-Image-Meta-Status": "active"}
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(403, response.status)
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("queued", response["x-image-meta-status"])

        # We allow 'setting' to the same status
        http = httplib2.Http()
        headers = {"X-Image-Meta-Status": "queued"}
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(200, response.status)
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("queued", response["x-image-meta-status"])

        # Make image active
        http = httplib2.Http()
        headers = {"Content-Type": "application/octet-stream"}
        response, content = http.request(path, "PUT", headers=headers, body="data")
        self.assertEqual(200, response.status)
        image = jsonutils.loads(content)["image"]
        self.assertEqual("active", image["status"])

        # Ensure status of 'active' image can't be changed
        http = httplib2.Http()
        headers = {"X-Image-Meta-Status": "queued"}
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(403, response.status)
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("active", response["x-image-meta-status"])

        # We allow 'setting' to the same status
        http = httplib2.Http()
        headers = {"X-Image-Meta-Status": "active"}
        response, content = http.request(path, "PUT", headers=headers)
        self.assertEqual(200, response.status)
        response, content = http.request(path, "HEAD")
        self.assertEqual(200, response.status)
        self.assertEqual("active", response["x-image-meta-status"])

        # Create a 'queued' image, ensure 'status' header is ignored
        http = httplib2.Http()
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        headers = {"Content-Type": "application/octet-stream", "X-Image-Meta-Status": "active"}
        response, content = http.request(path, "POST", headers=headers, body=None)
        self.assertEqual(201, response.status)
        image = jsonutils.loads(content)["image"]
        self.assertEqual("queued", image["status"])

        # Create an 'active' image, ensure 'status' header is ignored
        http = httplib2.Http()
        path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
        headers = {
            "Content-Type": "application/octet-stream",
            "X-Image-Meta-Disk-Format": "raw",
            "X-Image-Meta-Status": "queued",
            "X-Image-Meta-Container-Format": "bare",
        }
        response, content = http.request(path, "POST", headers=headers, body="data")
        self.assertEqual(201, response.status)
        image = jsonutils.loads(content)["image"]
        self.assertEqual("active", image["status"])
        self.stop_servers()
Ejemplo n.º 43
0
    def test_remote_image(self):
        """Verify an image added using a 'Location' header can be retrieved"""
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 1. POST /images with public image named Image1
        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 = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)

        image_id1 = data['image']['id']

        # 2. GET first image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s"
        args = ("127.0.0.1", self.api_port, image_id1)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))
        self.assertEqual(content, "*" * FIVE_KB)

        # 3. GET first image from registry in order to find S3 location
        path = "http://%s:%d/images/%s"
        args = ("127.0.0.1", self.registry_port, image_id1)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        loc = json.loads(content)['image']['location']
        s3_store_location = crypt.urlsafe_decrypt(key, loc)

        # 4. POST /images using location generated by Image1
        image_id2 = utils.generate_uuid()
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image2')
        headers['X-Image-Meta-Id'] = image_id2
        headers['X-Image-Meta-Location'] = s3_store_location
        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)
        # ensure data is refreshed, previously the size assertion
        # applied to the metadata returned from the previous GET
        data = json.loads(content)
        self.assertEqual(data['image']['size'], FIVE_KB)
        # checksum is not set for a remote image, as the image data
        # is not yet retrieved
        self.assertEqual(data['image']['checksum'], None)

        # 5. GET second image and make sure it can stream the image
        path = "http://%s:%d/v1/images/%s"
        args = ("127.0.0.1", self.api_port, image_id2)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))
        self.assertEqual(content, "*" * FIVE_KB)

        # 6. DELETE first and second images
        path = "http://%s:%d/v1/images/%s"
        args = ("127.0.0.1", self.api_port, image_id1)

        http = httplib2.Http()
        http.request(path % args, 'DELETE')

        path = "http://%s:%d/v1/images/%s"
        args = ("127.0.0.1", self.api_port, image_id2)

        http = httplib2.Http()
        http.request(path % args, 'DELETE')

        self.stop_servers()
Ejemplo n.º 44
0
    def test_private_images_notadmin(self):
        """
        Test that we can upload an owned image; that we can manipulate
        its is_public setting; and that appropriate authorization
        checks are applied to other (non-admin) users.
        """
        self.cleanup()
        self.start_servers()

        # First, we need to push an image up
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1', public=False)
        headers['X-Auth-Token'] = keystone_utils.pattieblack_token
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201)
        data = json.loads(content)
        self.assertEqual(data['image']['size'], FIVE_KB)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], False)
        self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)

        image_id = data['image']['id']

        # Next, make sure froggy can't list the image
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Shouldn't show up in the detail list, either
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, '{"images": []}')

        # Also check that froggy can't get the image metadata
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD', headers=headers)
        self.assertEqual(response.status, 404)

        # Froggy shouldn't be able to get the image, either.
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 404)

        # Froggy shouldn't be able to give themselves permission too
        # easily...
        headers = {'X-Auth-Token': keystone_utils.froggy_token,
                   'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 404)

        # Froggy shouldn't be able to give themselves ownership,
        # either
        headers = {'X-Auth-Token': keystone_utils.froggy_token,
                   'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 404)

        # Froggy can't delete it, either
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE', headers=headers)
        self.assertEqual(response.status, 404)

        # Pattieblack should be able to see the image in lists
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")

        # And in the detail list
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")
        self.assertEqual(data['images'][0]['is_public'], False)
        self.assertEqual(data['images'][0]['owner'],
                         keystone_utils.pattieblack_id)

        # Pattieblack should be able to get the image metadata
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # And of course the image itself
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "False")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # Pattieblack should be able to manipulate is_public
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token,
                   'X-Image-Meta-Is-Public': 'True'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)

        # Pattieblack can't give the image away, however
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token,
                   'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(data['image']['name'], "Image1")
        self.assertEqual(data['image']['is_public'], True)
        self.assertEqual(data['image']['owner'], keystone_utils.pattieblack_id)

        # Now that the image is public, froggy can see it
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")

        # Should also be in details
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/detail" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        data = json.loads(content)
        self.assertEqual(len(data['images']), 1)
        self.assertEqual(data['images'][0]['id'], image_id)
        self.assertEqual(data['images'][0]['size'], FIVE_KB)
        self.assertEqual(data['images'][0]['name'], "Image1")
        self.assertEqual(data['images'][0]['is_public'], True)
        self.assertEqual(data['images'][0]['owner'],
                         keystone_utils.pattieblack_id)

        # Froggy can get the image metadata now...
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'HEAD', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "True")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # And of course the image itself
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'GET', headers=headers)
        self.assertEqual(response.status, 200)
        self.assertEqual(content, "*" * FIVE_KB)
        self.assertEqual(response['x-image-meta-name'], "Image1")
        self.assertEqual(response['x-image-meta-is_public'], "True")
        self.assertEqual(response['x-image-meta-owner'],
                         keystone_utils.pattieblack_id)

        # Froggy still can't change is-public
        headers = {'X-Auth-Token': keystone_utils.froggy_token,
                   'X-Image-Meta-Is-Public': 'False'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Or give themselves ownership
        headers = {'X-Auth-Token': keystone_utils.froggy_token,
                   'X-Image-Meta-Owner': 'froggy'}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'PUT', headers=headers)
        self.assertEqual(response.status, 403)

        # Froggy can't delete it, either
        headers = {'X-Auth-Token': keystone_utils.froggy_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE', headers=headers)
        self.assertEqual(response.status, 403)

        # But pattieblack can
        headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
        path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
                                              image_id)
        http = httplib2.Http()
        response, content = http.request(path, 'DELETE', headers=headers)
        self.assertEqual(response.status, 200)

        self.stop_servers()
Ejemplo n.º 45
0
    def test_cache_middleware_transparent_v1(self):
        """
        We test that putting the cache middleware into the
        application pipeline gives us transparent image caching
        """
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # Add an image and 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(201, response.status)
        data = jsonutils.loads(content)
        self.assertEqual(
            hashlib.md5(image_data).hexdigest(), data['image']['checksum'])
        self.assertEqual(FIVE_KB, data['image']['size'])
        self.assertEqual("Image1", data['image']['name'])
        self.assertTrue(data['image']['is_public'])

        image_id = data['image']['id']

        # 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))

        # Grab the 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)

        # Verify image now in cache
        image_cached_path = os.path.join(self.api_server.image_cache_dir,
                                         image_id)

        # You might wonder why the heck this is here... well, it's here
        # because it took me forever to figure out that the disk write
        # cache in Linux was causing random failures of the os.path.exists
        # assert directly below this. Basically, since the cache is writing
        # the image file to disk in a different process, the write buffers
        # don't flush the cache file during an os.rename() properly, resulting
        # in a false negative on the file existence check below. This little
        # loop pauses the execution of this process for no more than 1.5
        # seconds. If after that time the cached image file still doesn't
        # appear on disk, something really is wrong, and the assert should
        # trigger...
        i = 0
        while not os.path.exists(image_cached_path) and i < 30:
            time.sleep(0.05)
            i = i + 1

        self.assertTrue(os.path.exists(image_cached_path))

        # Now, we delete the image from the server and verify that
        # the image cache no longer contains the deleted 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, 'DELETE')
        self.assertEqual(200, response.status)

        self.assertFalse(os.path.exists(image_cached_path))

        self.stop_servers()
Ejemplo n.º 46
0
    def test_remote_image(self):
        """Verify an image added using a 'Location' header can be retrieved"""
        self.cleanup()
        self.start_servers(**self.__dict__.copy())

        # 1. POST /images with public image named Image1
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image1')
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers,
                                         body=image_data)
        self.assertEqual(response.status, 201)
        data = json.loads(content)
        self.assertEqual(data['image']['checksum'],
                         hashlib.md5(image_data).hexdigest())
        self.assertEqual(data['image']['size'], FIVE_KB)

        image_id1 = data['image']['id']

        # 2. GET first image
        # Verify all information on image we just added is correct
        path = "http://%s:%d/v1/images/%s"
        args = ("0.0.0.0", self.api_port, image_id1)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))
        self.assertEqual(content, "*" * FIVE_KB)

        # 3. GET first image from registry in order to find S3 location
        path = "http://%s:%d/images/%s"
        args = ("0.0.0.0", self.registry_port, image_id1)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        if hasattr(self, 'metadata_encryption_key'):
            key = self.metadata_encryption_key
        else:
            key = self.api_server.metadata_encryption_key
        loc = json.loads(content)['image']['location']
        s3_store_location = crypt.urlsafe_decrypt(key, loc)

        # 4. POST /images using location generated by Image1
        image_id2 = utils.generate_uuid()
        image_data = "*" * FIVE_KB
        headers = minimal_headers('Image2')
        headers['X-Image-Meta-Id'] = image_id2
        headers['X-Image-Meta-Location'] = s3_store_location
        path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
        http = httplib2.Http()
        response, content = http.request(path, 'POST', headers=headers)
        self.assertEqual(response.status, 201)
        # ensure data is refreshed, previously the size assertion
        # applied to the metadata returned from the previous GET
        data = json.loads(content)
        self.assertEqual(data['image']['size'], FIVE_KB)
        # checksum is not set for a remote image, as the image data
        # is not yet retrieved
        self.assertEqual(data['image']['checksum'], None)

        # 5. GET second image and make sure it can stream the image
        path = "http://%s:%d/v1/images/%s"
        args = ("0.0.0.0", self.api_port, image_id2)

        http = httplib2.Http()
        response, content = http.request(path % args, 'GET')
        self.assertEqual(response.status, 200)
        self.assertEqual(response['content-length'], str(FIVE_KB))
        self.assertEqual(content, "*" * FIVE_KB)

        # 6. DELETE first and second images
        path = "http://%s:%d/v1/images/%s"
        args = ("0.0.0.0", self.api_port, image_id1)

        http = httplib2.Http()
        http.request(path % args, 'DELETE')

        path = "http://%s:%d/v1/images/%s"
        args = ("0.0.0.0", self.api_port, image_id2)

        http = httplib2.Http()
        http.request(path % args, 'DELETE')

        self.stop_servers()