Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
BurtBiel committed Mar 25, 2016
2 parents fafda81 + 0c48c28 commit dd77d3f
Show file tree
Hide file tree
Showing 13 changed files with 407 additions and 111 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,4 @@ src/build
/.vs/config/applicationhost.config

# Azure deployment credentials
*.pubxml

*.pubxml
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ pylint==1.5.4
pyyaml==3.11
six==1.10.0
vcrpy==1.7.4

#Same as: -e git+https://github.com/yugangw-msft/azure-activedirectory-library-for-python.git@device#egg=azure-activedirectory-library-for-python
http://40.112.211.51:8080/packages/adal-0.2.0.zip
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[bdist_wheel]
universal=1

[install]
[easy-install]
single-version-externally-managed=1
record=RECORD.txt
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python

#-------------------------------------------------------------------------
# Copyright (c) Microsoft. All rights reserved.
Expand Down Expand Up @@ -59,6 +59,7 @@
'azure==2.0.0rc1',
'six',
'jmespath',
'adal==0.2.0' #from internal index server.
]

with open('README.rst', 'r', encoding='utf-8') as f:
Expand Down
3 changes: 3 additions & 0 deletions src/azure/cli/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def configure_logging(argv, config):
logger.level = stderr_handler.level = level
logger.handlers.append(stderr_handler)

# Set logging level for all loggers
_logging.basicConfig(level=level)

if logfile:
# Configure the handler that logs code to a text file
log_handler = _logging.StreamHandler(open(logfile, 'w', encoding='utf-8'))
Expand Down
2 changes: 1 addition & 1 deletion src/azure/cli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
'login',
'logout',
'network',
'resourcegroup',
'resource',
'storage',
'taskhelp',
'vm',
Expand Down
9 changes: 4 additions & 5 deletions src/azure/cli/commands/_command_creation.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
from .._profile import Profile
import azure.cli._debug as _debug
import azure.cli as cli
from .._logging import logger

def get_mgmt_service_client(client_type, config_type):
profile = Profile()
config = config_type(*profile.get_login_credentials())
config.log_name = 'az'
config.log_level = logger.level

client = client_type(config)
_debug.allow_debug_connection(client)
client.config.add_user_agent("AZURECLI_{}".format(cli.__version__))

return client

def get_data_service_client(service_type, account_name, account_key):
client = service_type(account_name=account_name, account_key=account_key)
def get_data_service_client(service_type, account_name, account_key, connection_string=None):
client = service_type(account_name=account_name,
account_key=account_key,
connection_string=connection_string)
# TODO: enable Fiddler and user agent (task #115270703, #115270881)
return client
4 changes: 3 additions & 1 deletion src/azure/cli/commands/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ def list_subscriptions(args, unexpected): #pylint: disable=unused-argument

@command('account set')
@description(L('Set the current subscription'))
@option('--subscription-id -n <subscription-id>', L('Subscription Id, unique name also works.'))
@option('--subscription-id -n <subscription-id>',
L('Subscription Id, unique name also works.'),
required=True)
def set_active_subscription(args, unexpected): #pylint: disable=unused-argument
"""
type: command
Expand Down
71 changes: 44 additions & 27 deletions src/azure/cli/commands/login.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,61 @@
from msrestazure.azure_active_directory import UserPassCredentials, ServicePrincipalCredentials
from __future__ import print_function
from msrest.authentication import BasicTokenAuthentication
from adal import (acquire_token_with_username_password,
acquire_token_with_client_credentials,
acquire_user_code,
acquire_token_with_device_code)
from azure.mgmt.resource.subscriptions import (SubscriptionClient,
SubscriptionClientConfiguration)

from .._profile import Profile
from ..commands import command, description, option
from .._debug import should_disable_connection_verify
#TODO: update adal-python to support it
#from .._debug import should_disable_connection_verify
from .._locale import L

CLIENT_ID = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'

@command('login')
@description(L('log in to an Azure subscription using Active Directory Organization Id'))
@option('--username -u <username>',
L('organization Id or service principal. Microsoft Account is not yet supported.'),
required=True)
L('organization Id or service principal. Microsoft Account is not yet supported.'))
@option('--password -p <password>', L('user password or client secret, will prompt if not given.'))
@option('--service-principal', L('the credential represents a service principal.'))
@option('--tenant -t <tenant>', L('the tenant associated with the service principal.'))
def login(args, unexpected): #pylint: disable=unused-argument
interactive = False

username = args.get('username')
if username:
password = args.get('password')
if not password:
import getpass
password = getpass.getpass(L('Password: '))
else:
interactive = True

password = args.get('password')
if not password:
import getpass
password = getpass.getpass(L('Password: '))

cert_verify = not should_disable_connection_verify()
if args.get('service-principal'):
tenant = args.get('tenant')
if not tenant:
raise ValueError(L('Please supply tenant using "--tenant"'))

credentials = ServicePrincipalCredentials(username,
password,
tenant=tenant,
verify=cert_verify)
tenant = args.get('tenant')
authority = _get_authority_url(tenant)
if interactive:
user_code = acquire_user_code(authority)
print(user_code['message'])
credentials = acquire_token_with_device_code(authority, user_code)
username = credentials['userId']
else:
credentials = UserPassCredentials(username, #pylint: disable=redefined-variable-type
password,
client_id=CLIENT_ID,
verify=cert_verify)
if args.get('service-principal'):
if not tenant:
raise ValueError(L('Please supply tenant using "--tenant"'))

client = SubscriptionClient(SubscriptionClientConfiguration(credentials))
credentials = acquire_token_with_client_credentials(
authority,
username,
password)
else:
credentials = acquire_token_with_username_password(
authority,
username,
password)

token_credential = BasicTokenAuthentication({'access_token': credentials['accessToken']})
client = SubscriptionClient(SubscriptionClientConfiguration(token_credential))
subscriptions = client.subscriptions.list()

if not subscriptions:
Expand All @@ -50,6 +64,9 @@ def login(args, unexpected): #pylint: disable=unused-argument
#keep useful properties and not json serializable
profile = Profile()
consolidated = Profile.normalize_properties(username, subscriptions)
profile.set_subscriptions(consolidated, credentials.token['access_token'])
profile.set_subscriptions(consolidated, credentials['accessToken'])

return list(subscriptions)

def _get_authority_url(tenant=None):
return 'https://login.microsoftonline.com/{}'.format(tenant or 'common')
99 changes: 99 additions & 0 deletions src/azure/cli/commands/resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from .._argparse import IncorrectUsageError
from ..commands import command, description, option
from ._command_creation import get_mgmt_service_client
from .._locale import L

from azure.mgmt.resource.resources import (ResourceManagementClient,
ResourceManagementClientConfiguration)

@command('resource group list')
@description('List resource groups')
@option('--tag-name -tn <tagName>', L("the resource group's tag name"))
@option('--tag-value -tv <tagValue>', L("the resource group's tag value"))
def list_groups(args, unexpected): #pylint: disable=unused-argument
from azure.mgmt.resource.resources.models import ResourceGroup, ResourceGroupFilter

rmc = get_mgmt_service_client(ResourceManagementClient, ResourceManagementClientConfiguration)

filters = []
if args.get('tag-name'):
filters.append("tagname eq '{}'".format(args.get('tag-name')))
if args.get('tag-value'):
filters.append("tagvalue eq '{}'".format(args.get('tag-value')))

filter_text = ' and '.join(filters) if len(filters) > 0 else None

groups = rmc.resource_groups.list(filter=filter_text)
return list(groups)

@command('resource show')
@description(L('Show details of a specific resource in a resource group or subscription'))
@option('--resource-group -g <resourceGroup>', L('the resource group name'), required=True)
@option('--name -n <name>', L('the resource name'), required=True)
@option('--resource-type -r <resourceType>',
L('the resource type in format: <provider-namespace>/<type>'), required=True)
@option('--api-version -o <apiVersion>', L('the API version of the resource provider'))
@option('--parent <parent>',
L('the name of the parent resource (if needed), in <parent-type>/<parent-name> format'))
def show_resource(args, unexpected): #pylint: disable=unused-argument
rmc = get_mgmt_service_client(ResourceManagementClient, ResourceManagementClientConfiguration)

full_type = args.get('resource-type').split('/')
try:
provider_namespace = full_type[0]
resource_type = full_type[1]
except IndexError:
raise IncorrectUsageError('Parameter --resource-type must be in <namespace>/<type> format.')

api_version = _resolve_api_version(args, rmc)
if not api_version:
raise IncorrectUsageError(
L('API version is required and could not be resolved for resource {}'
.format(full_type)))

results = rmc.resources.get(
resource_group_name=args.get('resource-group'),
resource_name=args.get('name'),
resource_provider_namespace=provider_namespace,
resource_type=resource_type,
api_version=api_version,
parent_resource_path=args.get('parent', '')
)
return results

def _resolve_api_version(args, rmc):
api_version = args.get('api-version')
if api_version:
return api_version

# if api-version not supplied, attempt to resolve using provider namespace
parent = args.get('parent')
full_type = args.get('resource-type').split('/')
try:
provider_namespace = full_type[0]
resource_type = full_type[1]
except IndexError:
raise IncorrectUsageError('Parameter --resource-type must be in <namespace>/<type> format.')

if parent:
try:
parent_type = parent.split('/')[0]
except IndexError:
raise IncorrectUsageError('Parameter --parent must be in <type>/<name> format.')

resource_type = "{}/{}".format(parent_type, resource_type)
else:
resource_type = resource_type
provider = rmc.providers.get(provider_namespace)
for t in provider.resource_types:
if t.resource_type == resource_type:
# Return first non-preview version
for version in t.api_versions:
if not version.find('preview'):
return version
# No non-preview version found. Take first preview version
try:
return t.api_versions[0]
except IndexError:
return None
return None
27 changes: 0 additions & 27 deletions src/azure/cli/commands/resourcegroup.py

This file was deleted.

Loading

0 comments on commit dd77d3f

Please sign in to comment.