Repository: Azure/azure-cli

Issue:
How do I view the current account? `az account show` is not valid...
`azure account show` let's me see my active subscription... what's the equivalent in `azure-cli`?

IMO, `az account show` should just work


Discussion:
tjprescott: Also, one thing I've tried to do is when I "touch" a module I do a quick look through help to make sure there is acceptable help text for all commands and groups since we have a lot of gaps and help reflected from sloppy SDK docstrings. In this case it looks like it's just `az account list-locations` missing a short-summary, but it would be nice to add (save us another issue down the road).

Patch:
diff --git a/src/azure-cli-core/azure/cli/core/_profile.py b/src/azure-cli-core/azure/cli/core/_profile.py
index 01de246c9..c45f90b50 100644
--- a/src/azure-cli-core/azure/cli/core/_profile.py
+++ b/src/azure-cli-core/azure/cli/core/_profile.py
@@ -167,17 +167,16 @@ class Profile(object):
 
         self._cache_subscriptions_to_local_storage(subscriptions)
 
-    def set_active_subscription(self, subscription_id_or_name):
+    def set_active_subscription(self, subscription): #take id or name
         subscriptions = self.load_cached_subscriptions()
 
-        subscription_id_or_name = subscription_id_or_name.lower()
+        subscription = subscription.lower()
         result = [x for x in subscriptions
-                  if subscription_id_or_name == x[_SUBSCRIPTION_ID].lower() or
-                  subscription_id_or_name == x[_SUBSCRIPTION_NAME].lower()]
+                  if subscription in [x[_SUBSCRIPTION_ID].lower(), x[_SUBSCRIPTION_NAME].lower()]]
 
         if len(result) != 1:
             raise CLIError('The subscription of "{}" does not exist or has more than'
-                           ' one match.'.format(subscription_id_or_name))
+                           ' one match.'.format(subscription))
 
         for s in subscriptions:
             s[_IS_DEFAULT_SUBSCRIPTION] = False
@@ -218,14 +217,14 @@ class Profile(object):
 
         return active_account[_USER_ENTITY][_USER_NAME]
 
-    def get_subscription(self, subscription_id=None):
+    def get_subscription(self, subscription=None):#take id or name
         subscriptions = self.load_cached_subscriptions()
         if not subscriptions:
             raise CLIError("Please run 'az login' to setup account.")
 
         result = [x for x in subscriptions if (
-            subscription_id is None and x.get(_IS_DEFAULT_SUBSCRIPTION)) or
-                  (subscription_id == x.get(_SUBSCRIPTION_ID))]
+            not subscription and x.get(_IS_DEFAULT_SUBSCRIPTION) or
+            subscription and subscription.lower() in [x[_SUBSCRIPTION_ID].lower(), x[_SUBSCRIPTION_NAME].lower()])] #pylint: disable=line-too-long
         if len(result) != 1:
             raise CLIError("Please run 'az account set' to select active account.")
         return result[0]
diff --git a/src/azure-cli-core/azure/cli/core/application.py b/src/azure-cli-core/azure/cli/core/application.py
index 9315940ac..6039ba7c6 100644
--- a/src/azure-cli-core/azure/cli/core/application.py
+++ b/src/azure-cli-core/azure/cli/core/application.py
@@ -168,7 +168,6 @@ class Application(object):
     @staticmethod
     def _register_builtin_arguments(**kwargs):
         global_group = kwargs['global_group']
-        global_group.add_argument('--subscription', dest='_subscription_id', help=argparse.SUPPRESS)
         global_group.add_argument('--output', '-o', dest='_output_format',
                                   choices=['json', 'tsv', 'list', 'table', 'jsonc'],
                                   default=az_config.get('core', 'output', fallback='json'),
diff --git a/src/command_modules/azure-cli-container/azure/cli/command_modules/container/_params.py b/src/command_modules/azure-cli-container/azure/cli/command_modules/container/_params.py
index 9969227cf..99392b7ea 100644
--- a/src/command_modules/azure-cli-container/azure/cli/command_modules/container/_params.py
+++ b/src/command_modules/azure-cli-container/azure/cli/command_modules/container/_params.py
@@ -4,12 +4,19 @@
 #---------------------------------------------------------------------------------------------
 
 from azure.cli.core.commands import CliArgumentType, register_cli_argument
-from azure.cli.core.commands.parameters import (
-    name_type,
-    resource_group_name_type)
 
 # pylint: disable=line-too-long
 
+target_name = CliArgumentType(
+    options_list=('--target-name', '-n'),
+    help='Name of the Azure Container Service cluster to deploy containers to.'
+)
+
+target_resource_group = CliArgumentType(
+    options_list=('--target-resource-group', '-g'),
+    help='Name of the Azure Container Service cluster\'s resource group.'
+)
+
 registry_name = CliArgumentType(
     options_list=('--registry-name', '-r'),
     help='Azure container registry name. A new Azure container registry is created if omitted or does not exist.'
@@ -45,8 +52,8 @@ vsts_project_name = CliArgumentType(
     help='VSTS project name to create the build and release definitions. A new VSTS project is created if omitted or does not exist.'
 )
 
-register_cli_argument('container release create', 'name', name_type)
-register_cli_argument('container release create', 'resource_group_name', resource_group_name_type)
+register_cli_argument('container release create', 'target_name', target_name)
+register_cli_argument('container release create', 'target_resource_group', target_resource_group)
 register_cli_argument('container release create', 'registry_name', registry_name)
 register_cli_argument('container release create', 'registry_resource_id', registry_resource_id)
 register_cli_argument('container release create', 'remote_url', remote_url)
@@ -55,8 +62,8 @@ register_cli_argument('container release create', 'remote_access_token', remote_
 register_cli_argument('container release create', 'vsts_account_name', vsts_account_name)
 register_cli_argument('container release create', 'vsts_project_name', vsts_project_name)
 
-register_cli_argument('container build create', 'name', name_type)
-register_cli_argument('container build create', 'resource_group_name', resource_group_name_type)
+register_cli_argument('container build create', 'target_name', target_name)
+register_cli_argument('container build create', 'target_resource_group', target_resource_group)
 register_cli_argument('container build create', 'registry_name', registry_name)
 register_cli_argument('container build create', 'registry_resource_id', registry_resource_id)
 register_cli_argument('container build create', 'remote_url', remote_url)
@@ -65,5 +72,5 @@ register_cli_argument('container build create', 'remote_access_token', remote_ac
 register_cli_argument('container build create', 'vsts_account_name', vsts_account_name)
 register_cli_argument('container build create', 'vsts_project_name', vsts_project_name)
 
-register_cli_argument('container release list', 'name', name_type)
-register_cli_argument('container release list', 'resource_group_name', resource_group_name_type)
+register_cli_argument('container release list', 'target_name', target_name)
+register_cli_argument('container release list', 'target_resource_group', target_resource_group)
diff --git a/src/command_modules/azure-cli-container/azure/cli/command_modules/container/custom.py b/src/command_modules/azure-cli-container/azure/cli/command_modules/container/custom.py
index d2e04d50a..aafbefde9 100644
--- a/src/command_modules/azure-cli-container/azure/cli/command_modules/container/custom.py
+++ b/src/command_modules/azure-cli-container/azure/cli/command_modules/container/custom.py
@@ -17,15 +17,13 @@ from azure.cli.core._profile import Profile
 from azure.cli.core._util import CLIError
 
 logger = _logging.get_az_logger(__name__)
-BASE_URL = "https://management.azure.com"
-RESOURCE_BASE_URL = "/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}"
-CONTAINER_SERVICE_BASE_URL = RESOURCE_BASE_URL + "/providers/Microsoft.ContainerService"
-CONTAINER_SERVICE_RESOURCE_URL = (CONTAINER_SERVICE_BASE_URL +
-                                  "/containerServices/{container_service_name}")
-VISUAL_STUDIO_BASE_URL = RESOURCE_BASE_URL + "/providers/microsoft.visualstudio"
-VISUAL_STUDIO_ACCOUNT_URL = VISUAL_STUDIO_BASE_URL + "/account/{vsts_account_name}"
-VISUAL_STUDIO_PROJECT_URL = VISUAL_STUDIO_ACCOUNT_URL + "/project/{vsts_project_name}"
-RP_URL = BASE_URL + CONTAINER_SERVICE_RESOURCE_URL + "/providers/Microsoft.Mindaro"
+BASE_URL = "https://westus.mindaro.microsoft.io"
+SUBSCRIPTION_URL = "/subscriptions/{subscription_id}"
+RESOURCE_BASE_URL = SUBSCRIPTION_URL + "/resourceGroups/{resource_group_name}"
+CONTAINER_SERVICE_PROVIDER = "/providers/Microsoft.ContainerService"
+CONTAINER_SERVICE_RESOURCE_URL = (RESOURCE_BASE_URL + CONTAINER_SERVICE_PROVIDER + "/containerServices/{container_service_name}")
+
+SERVICE_URL = BASE_URL + SUBSCRIPTION_URL
 API_VERSION = "2016-11-01-preview"
 
 DOCKERFILE_FILE = 'Dockerfile'
@@ -33,9 +31,14 @@ DOCKER_COMPOSE_FILE = 'docker-compose.yml'
 DOCKER_COMPOSE_TEST_FILE = 'docker-compose.test.yml'
 DOCKER_COMPOSE_EXPECTED_VERSION = '2'
 
+DOCKERFILE_FILE = 'Dockerfile'
+DOCKER_COMPOSE_FILE = 'docker-compose.yml'
+DOCKER_COMPOSE_TEST_FILE = 'docker-compose.test.yml'
+DOCKER_COMPOSE_EXPECTED_VERSION = '2'
+
 def add_release(
-        name,
-        resource_group_name,
+        target_name,
+        target_resource_group,
         remote_url=None,
         remote_branch=None,
         remote_access_token=None,
@@ -46,10 +49,10 @@ def add_release(
     """
     Creates a build definition that automates building and pushing Docker images to an Azure container registry, and creates a release definition that automates deploying container images from a container registry to an Azure container service. Source repository must define a docker-compose.yml file.
 
-    :param name: Name of the target Azure container service instance to deploy containers to.
-    :type name: String
-    :param resource_group_name: Name of Azure container service's resource group.
-    :type resource_group_name: String
+    :param target_name: Name of the target Azure container service instance to deploy containers to.
+    :type target_name: String
+    :param target_resource_group: Name of Azure container service's resource group.
+    :type target_resource_group: String
     :param remote_url: Remote url of the GitHub or VSTS source repository that will be built and deployed. If omitted, a source repository will be searched for in the current working directory.
     :type remote_url: String
     :param remote_branch: Remote branch of the GitHub or VSTS source repository that will be built and deployed. If omitted refs/heads/master will be selected.
@@ -73,8 +76,8 @@ def add_release(
 
     # Call the RP
     return _call_rp_configure_cicd(
-        name,
-        resource_group_name,
+        target_name,
+        target_resource_group,
         vsts_account_name,
         vsts_project_name,
         registry_name,
@@ -112,8 +115,8 @@ def _get_repo_type(remote_url):
     return None
 
 def _call_rp_configure_cicd(
-        name,
-        resource_group_name,
+        target_name,
+        target_resource_group,
         vsts_account_name,
         vsts_project_name,
         registry_name,
@@ -125,10 +128,10 @@ def _call_rp_configure_cicd(
     """
     Calls the RP to build and deploy the service(s) in the cluster.
 
-    :param name: Name of the target Azure container service instance to deploy containers to.
-    :type name: String
-    :param resource_group_name: Name of Azure container service's resource group.
-    :type resource_group_name: String
+    :param target_name: Name of the target Azure container service instance to deploy containers to.
+    :type target_name: String
+    :param target_resource_group: Name of Azure container service's resource group.
+    :type target_resource_group: String
     :param remote_url: Remote url of the GitHub or VSTS source repository that will be built and deployed. If omitted, a source repository will be searched for in the current working directory.
     :type remote_url: String
     :param remote_branch: Remote branch of the GitHub or VSTS source repository that will be built and deployed. If omitted refs/heads/master will be selected.
@@ -150,11 +153,11 @@ def _call_rp_configure_cicd(
     cred, subscription_id, _ = profile.get_login_credentials()
 
     o_auth_token = cred.signed_session().headers['Authorization']
-
+    container_service_resource_id = CONTAINER_SERVICE_RESOURCE_URL.format(subscription_id=subscription_id, resource_group_name=target_resource_group, container_service_name=target_name)
     data = {
+        'acsResourceId': container_service_resource_id,
         'vstsAccountName': vsts_account_name,
         'vstsProjectName': vsts_project_name,
-        'token': o_auth_token,
         'registryName': registry_name,
         'registryResourceId': registry_resource_id,
         'remoteToken': remote_access_token,
@@ -163,10 +166,8 @@ def _call_rp_configure_cicd(
         'createRelease' : create_release
     }
 
-    configure_ci_cd_url = RP_URL.format(
-        subscription_id=subscription_id,
-        resource_group_name=resource_group_name,
-        container_service_name=name) + '/configureCI?api-version=' + API_VERSION
+    configure_ci_cd_url = SERVICE_URL.format(
+        subscription_id=subscription_id) + '/configureCI?api-version=' + API_VERSION
 
     headers = {'Content-type': 'application/json', 'Authorization': o_auth_token}
     req = requests.post(configure_ci_cd_url, data=json.dumps(data), headers=headers, timeout=600)
@@ -179,27 +180,26 @@ def _call_rp_configure_cicd(
     json_request = req.json()
     return json_request
 
-def list_releases(name, resource_group_name):
+def list_releases(target_name, target_resource_group):
     """
     Lists all the release definitions that are deployed to a given Azure container service.
 
-    :param name: Name of the target Azure container service instance.
-    :type name: String
-    :param resource_group_name: Name of Azure container service's resource group.
-    :type resource_group_name: String
+    :param target_name: Name of the target Azure container service instance.
+    :type target_name: String
+    :param target_resource_group: Name of Azure container service's resource group.
+    :type target_resource_group: String
     """
     profile = Profile()
     cred, subscription_id, _ = profile.get_login_credentials()
 
     o_auth_token = cred.signed_session().headers['Authorization']
+    container_service_resource_id = CONTAINER_SERVICE_RESOURCE_URL.format(subscription_id=subscription_id, resource_group_name=target_resource_group, container_service_name=target_name)
     data = {
-        'token': o_auth_token
+        'acsResourceId': container_service_resource_id
     }
 
-    list_releases_url = RP_URL.format(
-        subscription_id=subscription_id,
-        resource_group_name=resource_group_name,
-        container_service_name=name) + '/configureCI/1/listReleases?api-version=' + API_VERSION
+    list_releases_url = SERVICE_URL.format(
+        subscription_id=subscription_id) + '/listReleases?api-version=' + API_VERSION
 
     headers = {'Content-type': 'application/json', 'Authorization': o_auth_token}
     req = requests.post(list_releases_url, data=json.dumps(data), headers=headers, timeout=600)
@@ -308,8 +308,8 @@ def _check_registry_information(registry_name, registry_resource_id):
         raise CLIError("Please provide only one of registry-name and registry-resource-id, not both.")
 
 def add_ci(
-        name,
-        resource_group_name,
+        target_name,
+        target_resource_group,
         remote_url=None,
         remote_branch=None,
         remote_access_token=None,
@@ -345,8 +345,8 @@ def add_ci(
 
     # Call the RP
     return _call_rp_configure_cicd(
-        name,
-        resource_group_name,
+        target_name,
+        target_resource_group,
         vsts_account_name,
         vsts_project_name,
         registry_name,
diff --git a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_help.py b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_help.py
index 3752e4c92..c5eca10cb 100644
--- a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_help.py
+++ b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_help.py
@@ -22,4 +22,16 @@ helps['login'] = """
 helps['account'] = """
     type: group
     short-summary: Manages stored and default subscriptions
-"""
\ No newline at end of file
+"""
+
+helps['account list-locations'] = """
+    type: command
+    short-summary: list supported regions of the current subscription
+"""
+
+helps['account show'] = """
+    type: command
+    short-summary: show detail of the current subscription
+"""
+
+
diff --git a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_params.py b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_params.py
index b6ab41532..f6d727a03 100644
--- a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_params.py
+++ b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/_params.py
@@ -23,5 +23,5 @@ register_cli_argument('login', 'tenant', options_list=('--tenant', '-t'), help='
 
 register_cli_argument('logout', 'username', help='account user, if missing, logout the current active account')
 
-register_cli_argument('account', 'subscription_name_or_id', options_list=('--name', '-n'), help='Name or ID of subscription.', completer=get_subscription_id_list)
-register_cli_argument('account list', 'list_all', options_list=('--all',), help='List all subscriptions', action='store_true')
+register_cli_argument('account', 'subscription', help='Name or ID of subscription.', completer=get_subscription_id_list)
+register_cli_argument('account list', 'list_all', options_list=('--all',), help='List all subscriptions across all cloud environments', action='store_true')
diff --git a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/commands.py b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/commands.py
index 402b3f313..b10919682 100644
--- a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/commands.py
+++ b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/commands.py
@@ -11,6 +11,7 @@ from .custom import (login,
                      logout,
                      list_locations,
                      list_subscriptions,
+                     show_subscription,
                      set_active_subscription,
                      account_clear)
 
@@ -18,7 +19,9 @@ cli_command('login', login)
 cli_command('logout', logout)
 
 cli_command('account list', list_subscriptions)
+cli_command('account show', show_subscription)
 cli_command('account set', set_active_subscription)
 cli_command('account clear', account_clear)
 cli_command('account list-locations', list_locations)
 
+
diff --git a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/custom.py b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/custom.py
index 7a6912731..338049b18 100644
--- a/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/custom.py
+++ b/src/command_modules/azure-cli-profile/azure/cli/command_modules/profile/custom.py
@@ -27,12 +27,16 @@ def list_subscriptions(list_all=False): # pylint: disable=redefined-builtin
         sub['cloudName'] = sub.pop('environmentName', None)
     return [sub for sub in subscriptions if list_all or sub['cloudName'] == CLOUD.name]
 
-def set_active_subscription(subscription_name_or_id):
+def show_subscription(subscription=None):
+    profile = Profile()
+    return profile.get_subscription(subscription)
+
+def set_active_subscription(subscription):
     '''Set the current subscription'''
     if not id:
         raise CLIError('Please provide subscription id or unique name.')
     profile = Profile()
-    profile.set_active_subscription(subscription_name_or_id)
+    profile.set_active_subscription(subscription)
 
 def account_clear():
     '''Clear all stored subscriptions. To clear individual, use \'logout\''''


Test patch:
diff --git a/src/azure-cli-core/azure/cli/core/tests/test_profile.py b/src/azure-cli-core/azure/cli/core/tests/test_profile.py
index 64a05fd98..8d5fa3b31 100644
--- a/src/azure-cli-core/azure/cli/core/tests/test_profile.py
+++ b/src/azure-cli-core/azure/cli/core/tests/test_profile.py
@@ -10,6 +10,7 @@ import mock
 from azure.mgmt.resource.subscriptions.models import (SubscriptionState, Subscription,
                                                       SubscriptionPolicies, spendingLimit)
 from azure.cli.core._profile import Profile, CredsCache, SubscriptionFinder, CLOUD
+from azure.cli.core._util import CLIError
 
 class Test_Profile(unittest.TestCase):
 
@@ -164,6 +165,24 @@ class Test_Profile(unittest.TestCase):
         self.assertFalse(subscription2['isDefault'])
         self.assertTrue(subscription1['isDefault'])
 
+    def test_get_subscription(self):
+        storage_mock = {'subscriptions': None}
+        profile = Profile(storage_mock)
+
+        consolidated = Profile._normalize_properties(self.user1,
+                                                     [self.subscription1],
+                                                     False)
+        profile._set_subscriptions(consolidated)
+
+        self.assertEqual(self.display_name1, profile.get_subscription()['name'])
+        self.assertEqual(self.display_name1,
+                         profile.get_subscription(subscription=self.display_name1)['name'])
+
+        sub_id = self.id1.split('/')[-1]
+        self.assertEqual(sub_id, profile.get_subscription()['id'])
+        self.assertEqual(sub_id, profile.get_subscription(subscription=sub_id)['id'])
+        self.assertRaises(CLIError, profile.get_subscription, "random_id")
+
     @mock.patch('azure.cli.core._profile._load_tokens_from_file', autospec=True)
     def test_get_current_account_user(self, mock_read_cred_file):
         #setup