From a01bf55d2065ec1a98f486109cc8d315def501cd Mon Sep 17 00:00:00 2001
From: jiangpch <jiangpengcheng@navercorp.com>
Date: Thu, 13 Jul 2017 04:58:00 -0400
Subject: [PATCH] Fix 'domain' filter not work well in some commands

The 'domain' filter not work well in commands 'project show',
'user show' and 'user set'.

Depends-On: I490900d6249f01654d4cba43bddd3e7af7928a84
Closes-Bug: #1704097
Change-Id: Ib4f47cbaba27eb56c4a41d187fee74a995e62dc7
---
 openstackclient/identity/common.py            |  8 +++-
 openstackclient/identity/v3/project.py        |  3 +-
 openstackclient/identity/v3/user.py           |  6 ++-
 .../tests/unit/identity/v3/test_project.py    | 46 +++++++++++++++++++
 .../tests/unit/identity/v3/test_user.py       | 38 ++++++++++++++-
 .../notes/bug-1704097-8ff1ce1444b81b04.yaml   |  9 ++++
 6 files changed, 105 insertions(+), 5 deletions(-)
 create mode 100644 releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml

diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py
index 1f645b7d9c..3dc5adbbd2 100644
--- a/openstackclient/identity/common.py
+++ b/openstackclient/identity/common.py
@@ -58,7 +58,7 @@ def find_service(identity_client, name_type_or_id):
         raise exceptions.CommandError(msg % name_type_or_id)
 
 
-def _get_token_resource(client, resource, parsed_name):
+def _get_token_resource(client, resource, parsed_name, parsed_domain=None):
     """Peek into the user's auth token to get resource IDs
 
     Look into a user's token to try and find the ID of a domain, project or
@@ -71,6 +71,8 @@ def _get_token_resource(client, resource, parsed_name):
                      `project_domain`, `user_domain`, `project`, or `user`.
     :param parsed_name: This is input from parsed_args that the user is hoping
                         to find in the token.
+    :param parsed_domain: This is domain filter from parsed_args that used to
+                          filter the results.
 
     :returns: The ID of the resource from the token, or the original value from
               parsed_args if it does not match.
@@ -85,6 +87,10 @@ def _get_token_resource(client, resource, parsed_name):
         if resource == 'domain':
             token_dict = token_dict['project']
         obj = token_dict[resource]
+
+        # user/project under different domain may has a same name
+        if parsed_domain and parsed_domain not in obj['domain'].values():
+            return parsed_name
         return obj['id'] if obj['name'] == parsed_name else parsed_name
     # diaper defense in case parsing the token fails
     except Exception:  # noqa
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 873ee9c73e..c7806ee178 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -360,7 +360,8 @@ class ShowProject(command.ShowOne):
         identity_client = self.app.client_manager.identity
 
         project_str = common._get_token_resource(identity_client, 'project',
-                                                 parsed_args.project)
+                                                 parsed_args.project,
+                                                 parsed_args.domain)
 
         if parsed_args.domain:
             domain = common.find_domain(identity_client, parsed_args.domain)
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index 9c289a6d8a..5f4fb544fe 100644
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -358,7 +358,8 @@ class SetUser(command.Command):
                           "when a user does not have a password."))
 
         user_str = common._get_token_resource(identity_client, 'user',
-                                              parsed_args.user)
+                                              parsed_args.user,
+                                              parsed_args.domain)
         if parsed_args.domain:
             domain = common.find_domain(identity_client, parsed_args.domain)
             user = utils.find_resource(identity_client.users,
@@ -473,7 +474,8 @@ class ShowUser(command.ShowOne):
         identity_client = self.app.client_manager.identity
 
         user_str = common._get_token_resource(identity_client, 'user',
-                                              parsed_args.user)
+                                              parsed_args.user,
+                                              parsed_args.domain)
         if parsed_args.domain:
             domain = common.find_domain(identity_client, parsed_args.domain)
             user = utils.find_resource(identity_client.users,
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
index 7be81153c4..2ce26c6416 100644
--- a/openstackclient/tests/unit/identity/v3/test_project.py
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -19,6 +19,7 @@ from mock import call
 from osc_lib import exceptions
 from osc_lib import utils
 
+from openstackclient.identity import common
 from openstackclient.identity.v3 import project
 from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
 
@@ -1060,3 +1061,48 @@ class TestProjectShow(TestProject):
             ['children-id'],
         )
         self.assertEqual(data, datalist)
+
+    def test_project_show_with_domain(self):
+        project = identity_fakes.FakeProject.create_one_project(
+            {"name": self.project.name})
+
+        self.app.client_manager.identity.tokens.get_token_data.return_value = \
+            {'token':
+             {'project':
+              {'domain': {"id": self.project.domain_id},
+               'name': self.project.name,
+               'id': self.project.id
+               }
+              }
+             }
+
+        identity_client = self.app.client_manager.identity
+        arglist = [
+            "--domain", self.domain.id,
+            project.name,
+        ]
+        verifylist = [
+            ('domain', self.domain.id),
+            ('project', project.name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        project_str = common._get_token_resource(identity_client, 'project',
+                                                 parsed_args.project,
+                                                 parsed_args.domain)
+        self.assertEqual(self.project.id, project_str)
+
+        arglist = [
+            "--domain", project.domain_id,
+            project.name,
+        ]
+        verifylist = [
+            ('domain', project.domain_id),
+            ('project', project.name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        project_str = common._get_token_resource(identity_client, 'project',
+                                                 parsed_args.project,
+                                                 parsed_args.domain)
+        self.assertEqual(project.name, project_str)
diff --git a/openstackclient/tests/unit/identity/v3/test_user.py b/openstackclient/tests/unit/identity/v3/test_user.py
index 2ce66e94a2..96f5076655 100644
--- a/openstackclient/tests/unit/identity/v3/test_user.py
+++ b/openstackclient/tests/unit/identity/v3/test_user.py
@@ -19,6 +19,7 @@ import mock
 from osc_lib import exceptions
 from osc_lib import utils
 
+from openstackclient.identity import common
 from openstackclient.identity.v3 import user
 from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
 
@@ -1091,7 +1092,7 @@ class TestUserShow(TestUser):
         self.app.client_manager.identity.tokens.get_token_data.return_value = \
             {'token':
              {'user':
-              {'domain': {},
+              {'domain': {'id': self.user.domain_id},
                'id': self.user.id,
                'name': self.user.name,
                }
@@ -1126,3 +1127,38 @@ class TestUserShow(TestUser):
             self.user.name,
         )
         self.assertEqual(datalist, data)
+
+    def test_user_show_with_domain(self):
+        user = identity_fakes.FakeUser.create_one_user(
+            {"name": self.user.name})
+        identity_client = self.app.client_manager.identity
+
+        arglist = [
+            "--domain", self.user.domain_id,
+            user.name,
+        ]
+        verifylist = [
+            ('domain', self.user.domain_id),
+            ('user', user.name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        user_str = common._get_token_resource(identity_client, 'user',
+                                              parsed_args.user,
+                                              parsed_args.domain)
+        self.assertEqual(self.user.id, user_str)
+
+        arglist = [
+            "--domain", user.domain_id,
+            user.name,
+        ]
+        verifylist = [
+            ('domain', user.domain_id),
+            ('user', user.name),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        user_str = common._get_token_resource(identity_client, 'user',
+                                              parsed_args.user,
+                                              parsed_args.domain)
+        self.assertEqual(user.name, user_str)
diff --git a/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml b/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml
new file mode 100644
index 0000000000..c20d0c9991
--- /dev/null
+++ b/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml
@@ -0,0 +1,9 @@
+---
+fixes:
+  - |
+    Fix an issue when run commands `project show`, `user show` and `user set`
+    with `--domain` specific, the domain filter won't work if the login user's
+    project name or user name is same with the resource name user hoping to
+    get.
+
+    [Bug `1704097 <https://bugs.launchpad.net/python-openstackclient/+bug/1704097>`_]