Replace glance.client with python-glanceclient

The legacy glance client code is going to be removed soon, so
Tempest needs to stop using it. This patch updates Tempest to
use the shiny new python-glanceclient library.

This requires python-glanceclient 0.5.1+ to work.

Fixes bug 1048716

Change-Id: I6e0773644ed1e4e19448a5899a71ee2ed5d36f82
diff --git a/tempest/manager.py b/tempest/manager.py
index 0679db9..2cac25e 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -18,7 +18,7 @@
 import logging
 
 # Default client libs
-import glance.client
+import glanceclient
 import keystoneclient.v2_0.client
 import novaclient.client
 import quantumclient.v2_0.client
@@ -131,30 +131,11 @@
                         no_cache=True)
 
     def _get_image_client(self):
-        host = self.config.images.host
-        port = self.config.images.port
-        strategy = self.config.identity.strategy
-        auth_url = self.config.identity.auth_url
-        username = self.config.images.username
-        password = self.config.images.password
-        tenant_name = self.config.images.tenant_name
-
-        if None in (host, port, username, password, tenant_name):
-            msg = ("Missing required credentials for image client. "
-                    "host:%(host)s, port: %(port)s username: %(username)s, "
-                    "password: %(password)s, "
-                    "tenant_name: %(tenant_name)s") % locals()
-            raise exceptions.InvalidConfiguration(msg)
-        auth_url = self.config.identity.auth_url.rstrip('tokens')
-
-        creds = {'strategy': strategy,
-                 'username': username,
-                 'password': password,
-                 'tenant': tenant_name,
-                 'auth_url': auth_url}
-
-        # Create our default Glance client to use in testing
-        return glance.client.Client(host, port, creds=creds)
+        keystone = self._get_identity_client()
+        token = keystone.auth_token
+        endpoint = keystone.service_catalog.url_for(service_type='image',
+                                                    endpoint_type='publicURL')
+        return glanceclient.Client('1', endpoint=endpoint, token=token)
 
     def _get_identity_client(self):
         # This identity client is not intended to check the security
diff --git a/tempest/services/image/service.py b/tempest/services/image/service.py
index 9cfe502..154b5b8 100644
--- a/tempest/services/image/service.py
+++ b/tempest/services/image/service.py
@@ -36,22 +36,25 @@
         # Determine the Images API version
         self.api_version = int(config.images.api_version)
 
+        # We load the client class specific to the API version...
         if self.api_version == 1:
-            # We load the client class specific to the API version...
-            from glance import client
-            creds = {
-                'username': config.images.username,
-                'password': config.images.password,
-                'tenant': config.images.tenant_name,
-                # rstrip() is necessary here because Glance client
-                # automatically adds the tokens/ part...
-                'auth_url': config.identity.auth_url.rstrip('/tokens'),
-                'strategy': config.identity.strategy
-            }
-            self._client = client.Client(config.images.host,
-                                         config.images.port,
-                                         creds=creds,
-                                         configure_via_auth=False)
+            import glanceclient
+            import keystoneclient.v2_0.client
+
+            auth_url = self.config.identity.auth_url.rstrip('tokens')
+            keystone = keystoneclient.v2_0.client.Client(
+                    username=config.images.username,
+                    password=config.images.password,
+                    tenant_name=config.images.tenant_name,
+                    auth_url=auth_url)
+            token = keystone.auth_token
+            endpoint = keystone.service_catalog.url_for(
+                    service_type='image',
+                    endpoint_type='publicURL')
+
+            self._client = glanceclient.Client('1',
+                                               endpoint=endpoint,
+                                               token=token)
         else:
             raise NotImplementedError
 
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/test_images.py
index 0e515dc..c6b903b 100644
--- a/tempest/tests/image/test_images.py
+++ b/tempest/tests/image/test_images.py
@@ -25,8 +25,7 @@
 
 GLANCE_INSTALLED = False
 try:
-    from glance import client
-    from glance.common import exception
+    import glanceclient
     GLANCE_INSTALLED = True
 except ImportError:
     pass
@@ -51,7 +50,7 @@
     @classmethod
     def tearDownClass(cls):
         for image_id in cls.created_images:
-            cls.client.delete_image(image_id)
+            cls.client.images.delete(image_id)
 
     @attr(type='image')
     def test_register_with_invalid_data(self):
@@ -70,11 +69,10 @@
         ]
         for meta in metas:
             try:
-                results = self.client.add_image(meta)
-            except exception.Invalid:
+                self.client.images.create(**meta)
+            except glanceclient.exc.HTTPBadRequest:
                 continue
-            self.fail("Did not raise Invalid for meta %s. Got results: %s" %
-                      (meta, results))
+            self.fail("Did not raise Invalid for meta %s." % meta)
 
     @attr(type='image')
     def test_register_then_upload(self):
@@ -86,27 +84,27 @@
             'container_format': 'bare',
             'properties': {'prop1': 'val1'}
         }
-        results = self.client.add_image(meta)
-        self.assertTrue('id' in results)
-        image_id = results['id']
+        results = self.client.images.create(**meta)
+        self.assertTrue(hasattr(results, 'id'))
+        image_id = results.id
         self.created_images.append(image_id)
-        self.assertTrue('name' in results)
-        self.assertEqual(meta['name'], results['name'])
-        self.assertTrue('is_public' in results)
-        self.assertEqual(meta['is_public'], results['is_public'])
-        self.assertTrue('status' in results)
-        self.assertEqual('queued', results['status'])
-        self.assertTrue('properties' in results)
+        self.assertTrue(hasattr(results, 'name'))
+        self.assertEqual(meta['name'], results.name)
+        self.assertTrue(hasattr(results, 'is_public'))
+        self.assertEqual(meta['is_public'], results.is_public)
+        self.assertTrue(hasattr(results, 'status'))
+        self.assertEqual('queued', results.status)
+        self.assertTrue(hasattr(results, 'properties'))
         for key, val in meta['properties'].items():
-            self.assertEqual(val, results['properties'][key])
+            self.assertEqual(val, results.properties[key])
 
         # Now try uploading an image file
         image_file = StringIO.StringIO('*' * 1024)
-        results = self.client.update_image(image_id, image_data=image_file)
-        self.assertTrue('status' in results)
-        self.assertEqual('active', results['status'])
-        self.assertTrue('size' in results)
-        self.assertEqual(1024, results['size'])
+        results = self.client.images.update(image_id, data=image_file)
+        self.assertTrue(hasattr(results, 'status'))
+        self.assertEqual('active', results.status)
+        self.assertTrue(hasattr(results, 'size'))
+        self.assertEqual(1024, results.size)
 
     @attr(type='image')
     def test_register_remote_image(self):
@@ -118,16 +116,16 @@
             'container_format': 'bare',
             'location': 'http://example.com/someimage.iso'
         }
-        results = self.client.add_image(meta)
-        self.assertTrue('id' in results)
-        image_id = results['id']
+        results = self.client.images.create(**meta)
+        self.assertTrue(hasattr(results, 'id'))
+        image_id = results.id
         self.created_images.append(image_id)
-        self.assertTrue('name' in results)
-        self.assertEqual(meta['name'], results['name'])
-        self.assertTrue('is_public' in results)
-        self.assertEqual(meta['is_public'], results['is_public'])
-        self.assertTrue('status' in results)
-        self.assertEqual('active', results['status'])
+        self.assertTrue(hasattr(results, 'name'))
+        self.assertEqual(meta['name'], results.name)
+        self.assertTrue(hasattr(results, 'is_public'))
+        self.assertEqual(meta['is_public'], results.is_public)
+        self.assertTrue(hasattr(results, 'status'))
+        self.assertEqual('active', results.status)
 
 
 class ListImagesTest(unittest.TestCase):
@@ -143,7 +141,7 @@
         cls.os = openstack.ServiceManager()
         cls.client = cls.os.images.get_client()
         cls.created_images = []
-        cls.original_images = cls.client.get_images()
+        cls.original_images = list(cls.client.images.list())
 
         # We add a few images here to test the listing functionality of
         # the images API
@@ -157,7 +155,7 @@
     @classmethod
     def tearDownClass(cls):
         for image_id in cls.created_images:
-            cls.client.delete_image(image_id)
+            cls.client.images.delete(image_id)
 
     @classmethod
     def _create_remote_image(cls, x):
@@ -172,8 +170,8 @@
             'container_format': 'bare',
             'location': 'http://example.com/someimage_%s.iso' % x
         }
-        results = cls.client.add_image(meta)
-        image_id = results['id']
+        results = cls.client.images.create(**meta)
+        image_id = results.id
         return image_id
 
     @classmethod
@@ -183,15 +181,16 @@
         image. Note that the size of the new image is a random number between
         1024 and 4096
         """
+        image_file = StringIO.StringIO('*' * random.randint(1024, 4096))
         meta = {
             'name': 'New Standard Image %s' % x,
             'is_public': True,
             'disk_format': 'raw',
-            'container_format': 'bare'
+            'container_format': 'bare',
+            'data': image_file,
         }
-        image_file = StringIO.StringIO('*' * random.randint(1024, 4096))
-        results = cls.client.add_image(meta, image_file)
-        image_id = results['id']
+        results = cls.client.images.create(**meta)
+        image_id = results.id
         return image_id
 
     @attr(type='image')
@@ -199,5 +198,5 @@
         """
         Simple test to see all fixture images returned
         """
-        images = self.client.get_images()
+        images = list(self.client.images.list())
         self.assertEqual(10, len(images) - len(self.original_images))