{"body":"notmorgan@braavos:~/openstack/shade$ git diff\ndiff --git a/shade/_tasks.py b/shade/_tasks.py\nindex c350510..1b29b52 100644\n--- a/shade/_tasks.py\n+++ b/shade/_tasks.py\n@@ -17,11 +17,6 @@\n from shade import task_manager\n \n \n-class UserList(task_manager.Task):\n-    def main(self, client):\n-        return client.keystone_client.users.list()\n-\n-\n class UserCreate(task_manager.Task):\n     def main(self, client):\n         return client.keystone_client.users.create(**self.args)\ndiff --git a/shade/openstackcloud.py b/shade/openstackcloud.py\nindex 88e58d6..3e2fd08 100644\n--- a/shade/openstackcloud.py\n+++ b/shade/openstackcloud.py\n@@ -414,6 +414,18 @@ class OpenStackCloud(\n     @property\n     def _identity_client(self):\n         if 'identity' not in self._raw_clients:\n+            # Get configured api version for downgrades\n+            config_version = self.cloud_config.get_api_version('identity')\n+            identity_client = self._get_raw_client('identity')\n+            identity_url = self.cloud_config.config.get('identity_endpoint_override')\n+            if not identity_url:\n+                image_url = self._discover_identity_endpoint(\n+                    config_version, identity_client)\n+            identity_client.endpoint_override = identity_url\n+            self._raw_clients['identity'] = identity_client\n+        return self._raw_clients['identity']\n+\n+        if 'identity' not in self._raw_clients:\n             self._raw_clients['identity'] = self._get_raw_client('identity')\n         return self._raw_clients['identity']\n \n@@ -424,20 +436,86 @@ class OpenStackCloud(\n             self._raw_clients['raw-image'] = image_client\n         return self._raw_clients['raw-image']\n \n-    def _match_given_image_endpoint(self, given, version):\n+    def _match_given_endpoint(self, given, version):\n         if given.endswith('/'):\n             given = given[:-1]\n         if given.split('/')[-1].startswith('v' + version[0]):\n             return True\n         return False\n \n+    def _discover_identity_endpoint(self, config_version, identity_client):\n+        try:\n+            # this is a replica of the _discover_image_endpoint, but\n+            # identity-specific. soooooooooooooo...\n+            # First - quick check to see if the endpoint in the catalog\n+            # is a versioned endpoint that matches the version we requested.\n+            # If it is, don't do any addtional work.\n+            catalog_endpoint = identity_client.get_endpoint()\n+            if self._match_given_endpoint(catalog_endpoint, config_version):\n+                return catalog_endpoint\n+            # version discovery\n+            versions = identity_client.get('/')['values']\n+            api_version = None\n+            if config_version.startswith('2'):\n+                api_version = [\n+                    version for version in versions\n+                    if version['id'] == 'v2.0']\n+                if api_version:\n+                    api_version = api_version[0]\n+            if config_version.startswith('3'):\n+                api_version = [\n+                    version for version in versions\n+                    if version['id'].startswith('v3')][0]\n+            identity_url = api_version['links'][0]['href']\n+            # If we detect a different version that was configured,\n+            # set the version in occ because we have logic elsewhere\n+            # that is different depending on which version we're using\n+            warning_msg = None\n+            if (config_version.startswith('2')\n+                    and api_version['id'].startswith('v2')):\n+                self.cloud_config.config['identity_api_version'] = '3'\n+                warning_msg = (\n+                    'identity_api_version is 3 but only 2 is available.')\n+            elif (config_version.startswith('2')\n+                  and api_version['id'].startswith('v3')):\n+                self.cloud_config.config['identity_api_version'] = '2'\n+                warning_msg = (\n+                    'identity_api_version is 2 but only 3 is available.')\n+            if warning_msg:\n+                self.log.debug(warning_msg)\n+                warnings.warn(warning_msg)\n+\n+        except (keystoneauth1.exceptions.connection.ConnectFailure,\n+                OpenStackCloudURINotFound) as e:\n+            # A 404 or a connection error is a likely thing to get\n+            # either with a misconfgured glance. or we've already\n+            # gotten a versioned endpoint from the catalog\n+            self.log.debug(\n+                \"Keystone version discovery failed, assuming endpoint in\"\n+                \" the catalog is already versioned. {e}\".format(e=str(e)))\n+            identity_url = identity_client.get_endpoint()\n+\n+        # Sometimes version discovery documents have broken endpoints, but\n+        # the catalog has good ones (what?)\n+        catalog_endpoint = urllib.parse.urlparse(\n+            identity_client.get_endpoint())\n+        discovered_endpoint = urllib.parse.urlparse(identity_url)\n+\n+        return urllib.parse.ParseResult(\n+            catalog_endpoint.scheme,\n+            catalog_endpoint.netloc,\n+            discovered_endpoint.path,\n+            discovered_endpoint.params,\n+            discovered_endpoint.query,\n+            discovered_endpoint.fragment).geturl()\n+\n     def _discover_image_endpoint(self, config_version, image_client):\n         try:\n             # First - quick check to see if the endpoint in the catalog\n             # is a versioned endpoint that matches the version we requested.\n             # If it is, don't do any additoinal work.\n             catalog_endpoint = image_client.get_endpoint()\n-            if self._match_given_image_endpoint(\n+            if self._match_given_endpoint(\n                     catalog_endpoint, config_version):\n                 return catalog_endpoint\n             # Version discovery\n@@ -881,9 +959,12 @@ class OpenStackCloud(\n         :raises: ``OpenStackCloudException``: if something goes wrong during\n             the OpenStack API call.\n         \"\"\"\n-        with _utils.shade_exceptions(\"Failed to list users\"):\n-            users = self.manager.submit_task(_tasks.UserList())\n-        return _utils.normalize_users(users)\n+        version = self.cloud_config.get_api_version('identity')\n+        uri_parts = ['users']\n+        if version in ('3', ):\n+            uri_parts.insert(0, 'v3')\n+        rest_uri = '/'.join(uri_parts)\n+        return _utils.normalize_users(self._identity_client.get(rest_uri))\n \n     def search_users(self, name_or_id=None, filters=None):\n         \"\"\"Search users.\nnotmorgan@braavos:~/openstack/shade$ \n","name":"","extension":"txt","url":"https://www.irccloud.com/pastebin/UsVj0v82","modified":1495661919,"id":"UsVj0v82","size":6641,"lines":146,"own_paste":false,"theme":"","date":1495661919}