зеркало из https://github.com/microsoft/azure-cli.git
Merge branch 'master' into pip-requirements
Moved the pylint requirement to the requirements.txt file # Conflicts: # .travis.yml
This commit is contained in:
Коммит
2fc6d50d1c
|
@ -7,4 +7,6 @@ install:
|
|||
- pip install -r requirements.txt
|
||||
script:
|
||||
- export PYTHONPATH=$PATHONPATH:./src
|
||||
- python -m unittest discover -s src/azure/cli/tests
|
||||
- python -m azure.cli
|
||||
- pylint src/azure
|
||||
- python -m unittest discover -s src/azure/cli/tests
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
FROM ubuntu:14.04
|
||||
|
||||
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
|
||||
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install -qqy --no-install-recommends\
|
||||
build-essential \
|
||||
curl \
|
||||
ca-certificates \
|
||||
git \
|
||||
python-pip \
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
python-dev \
|
||||
vim \
|
||||
nano \
|
||||
jq && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
pip install azure==2.0.0a1 && \
|
||||
pip install --upgrade requests && \
|
||||
pip install cryptography && \
|
||||
pip install pyopenssl ndg-httpsclient pyasn1
|
||||
|
||||
ENV AZURECLITEMP /tmp/azure-cli
|
||||
ENV PYTHONPATH $PYTHONPATH:$AZURECLITEMP/src
|
||||
ENV PATH $PATH:$AZURECLITEMP
|
||||
|
||||
RUN mkdir -p $AZURECLITEMP
|
||||
ADD src $AZURECLITEMP/src
|
||||
|
||||
RUN echo '#!/bin/bash'>$AZURECLITEMP/az && \
|
||||
echo 'python -m azure.cli "$@"'>>$AZURECLITEMP/az && \
|
||||
chmod +x $AZURECLITEMP/az && \
|
||||
az
|
||||
|
||||
ENV EDITOR vim
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
export PYTHONPATH="${DIR}/src:${PYTHONPATH}"
|
||||
|
||||
python -m azure.cli "$@"
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
@echo off
|
||||
setlocal
|
||||
|
||||
SET PYTHONPATH=%~dp0/src;%PYTHONPATH%
|
||||
python -m azure.cli %*
|
||||
|
||||
endlocal
|
|
@ -14,6 +14,9 @@
|
|||
<LaunchProvider>Standard Python launcher</LaunchProvider>
|
||||
<InterpreterId>{1dd9c42b-5980-42ce-a2c3-46d3bf0eede4}</InterpreterId>
|
||||
<InterpreterVersion>3.5</InterpreterVersion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'" />
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'" />
|
||||
|
@ -25,15 +28,23 @@
|
|||
<Compile Include="azure\cli\commands\account.py" />
|
||||
<Compile Include="azure\cli\commands\login.py" />
|
||||
<Compile Include="azure\cli\commands\logout.py" />
|
||||
<Compile Include="azure\cli\commands\network.py" />
|
||||
<Compile Include="azure\cli\commands\resourcegroup.py" />
|
||||
<Compile Include="azure\cli\commands\storage.py" />
|
||||
<Compile Include="azure\cli\commands\vm.py" />
|
||||
<Compile Include="azure\cli\commands\_auto_command.py" />
|
||||
<Compile Include="azure\cli\commands\__init__.py" />
|
||||
<Compile Include="azure\cli\main.py" />
|
||||
<Compile Include="azure\cli\tests\test_argparse.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="azure\cli\tests\test_autocommand.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="azure\cli\tests\test_connection_verify.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="azure\cli\tests\test_output.py" />
|
||||
<Compile Include="azure\cli\tests\test_profile.py" />
|
||||
<Compile Include="azure\cli\_argparse.py" />
|
||||
<Compile Include="azure\cli\commands\_command_creation.py">
|
||||
|
@ -42,7 +53,9 @@
|
|||
<Compile Include="azure\cli\_debug.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="azure\cli\_locale.py" />
|
||||
<Compile Include="azure\cli\_logging.py" />
|
||||
<Compile Include="azure\cli\_output.py" />
|
||||
<Compile Include="azure\cli\_profile.py" />
|
||||
<Compile Include="azure\cli\_session.py">
|
||||
<SubType>Code</SubType>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
Setting up your development environment
|
||||
========================================
|
||||
The Azure Python CLI projects sources are located on GitHub (https://github.com/Azure/azure-cli/). In order to contribute to the project, you are expected to:
|
||||
- Have a GitHub account. For Microsoft contributors, follow the guidelines on https://opensourcehub.microsoft.com/ to create, configure and link your account
|
||||
- Fork the https://github.com/Azure/azure-cli/ repository into your private GitHub account
|
||||
- Create pull requests against the httips://github.com/azure/azure-cli repository to get your code changes merged into the project repository.
|
||||
|
||||
##Preparing your machine
|
||||
+ Install Python 3.5.x from http://python.org. Please note that the version of Python that comes preinstalled on OSX is 2.7.
|
||||
+ Clone your repository and check out the master branch
|
||||
+ Create a new virtual environment “env” for Python 3.5 in the root of your clone. You can do this by running:
|
||||
|
||||
Windows
|
||||
```BatchFile
|
||||
python.exe -m venv <clone root>\env
|
||||
```
|
||||
OSX/Ubuntu
|
||||
```Shell
|
||||
python –m venv <clone root>/env
|
||||
```
|
||||
|
||||
+ Activate the env virtual environment by running:
|
||||
|
||||
Windows:
|
||||
```BatchFile
|
||||
<clone root>\env\scripts\activate.bat
|
||||
```
|
||||
OSX/Ubuntu (bash):
|
||||
```Shell
|
||||
. <clone root>/env/bin/activate
|
||||
```
|
||||
|
||||
+ Install the latest autorest generated azure sdk.
|
||||
```Shell
|
||||
python –m pip install azure==2.0.0a1
|
||||
```
|
||||
+ Add <clone root>\src to your PYTHONPATH environment variable:
|
||||
|
||||
Windows:
|
||||
```BatchFile
|
||||
set PYTHONPATH=<clone root>\src;%PYTHONPATH%
|
||||
```
|
||||
OSX/Ubuntu (bash):
|
||||
```Shell
|
||||
export PYTHONPATH=<clone root>/src:${PYTHONPATH}
|
||||
```
|
||||
|
||||
##Configuring your IDE
|
||||
###Visual Studio (Windows only)
|
||||
+ Install Python Tools for Visual Studio. As of 2/18/2016, the current version (PTVS 2.2) can be found here.
|
||||
+ Open the azure-cli.pyproj project
|
||||
You should now be able to launch your project by pressing F5/start debugging
|
||||
|
||||
###Visual Studio Code (Any platform)
|
||||
Experimental steps – still haven’t been able to get virtual environments to work well with VSCode
|
||||
+ Install VS Code
|
||||
+ Install (one of) the python extension(s) (https://marketplace.visualstudio.com/items?itemName=donjayamanne.python)
|
||||
Debugging should now work (including stepping and setting breakpoints).
|
||||
|
||||
The repo has a launch.json file that will launch the version of Python that is first on your path.
|
||||
|
||||
##Running unit tests:
|
||||
|
||||
###Command line:
|
||||
If you have configured your PYTHONPATH correctly (see above), you should be able to run all unit tests by executing python -m unittest from your <clone root>/src directory.
|
||||
|
||||
###VS Code:
|
||||
<Working on it>
|
||||
|
||||
###Visual Studio
|
||||
<Working on it>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
[MESSAGES CONTROL]
|
||||
# For all codes, run 'pylint --list-msgs' or go to 'http://pylint-messages.wikidot.com/all-codes'
|
||||
# C0111 Missing docstring
|
||||
# C0103 Invalid %s name "%s"
|
||||
# I0011 Warning locally suppressed using disable-msg
|
||||
# W0511 fixme
|
||||
disable=C0111,C0103,I0011,W0511
|
||||
[DESIGN]
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=25
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=20
|
|
@ -1,3 +1,3 @@
|
|||
azure==2.0.0a1
|
||||
mock==1.3.0
|
||||
|
||||
pylint==1.5.4
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
from __future__ import print_function
|
||||
import json
|
||||
import os
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
|
||||
from ._locale import get_file as locale_get_file
|
||||
from ._locale import L, get_file as locale_get_file
|
||||
from ._logging import logger
|
||||
|
||||
# Named arguments are prefixed with one of these strings
|
||||
|
@ -20,7 +18,7 @@ class IncorrectUsageError(Exception):
|
|||
pass
|
||||
|
||||
class Arguments(dict):
|
||||
def __init__(self, source=None):
|
||||
def __init__(self, source=None): #pylint: disable=super-init-not-called
|
||||
self.positional = []
|
||||
if source:
|
||||
self.update(source)
|
||||
|
@ -40,7 +38,7 @@ class Arguments(dict):
|
|||
except LookupError:
|
||||
pass
|
||||
logger.debug('Argument %s is required', key)
|
||||
raise IncorrectUsageError(_("Argument {0} is required").format(key))
|
||||
raise IncorrectUsageError(L('Argument {0} is required').format(key))
|
||||
|
||||
def _read_arg(string):
|
||||
for prefix in ARG_PREFIXES:
|
||||
|
@ -66,11 +64,15 @@ class ArgumentParser(object):
|
|||
self.noun_map = {
|
||||
'$doc': 'azure-cli.txt',
|
||||
}
|
||||
self.help_args = { '--help', '-h' }
|
||||
self.complete_args = { '--complete' }
|
||||
self.global_args = { '--verbose', '--debug' }
|
||||
self.help_args = {'--help', '-h'}
|
||||
self.complete_args = {'--complete'}
|
||||
self.global_args = {'--verbose', '--debug'}
|
||||
|
||||
def add_command(self, handler, name=None, description=None, args=None):
|
||||
def add_command(self,
|
||||
handler,
|
||||
name=None,
|
||||
description=None,
|
||||
args=None):
|
||||
'''Registers a command that may be parsed by this parser.
|
||||
|
||||
`handler` is the function to call with two `Arguments` objects.
|
||||
|
@ -105,7 +107,7 @@ class ArgumentParser(object):
|
|||
m['$args'] = []
|
||||
m['$kwargs'] = kw = {}
|
||||
m['$argdoc'] = ad = []
|
||||
for spec, desc in (args or []):
|
||||
for spec, desc in args or []:
|
||||
if not any(spec.startswith(p) for p in ARG_PREFIXES):
|
||||
m['$args'].append(spec.strip('<> '))
|
||||
ad.append((spec, desc))
|
||||
|
@ -121,7 +123,11 @@ class ArgumentParser(object):
|
|||
ad.append(('/'.join(aliases), desc))
|
||||
|
||||
|
||||
def execute(self, args, show_usage=False, show_completions=False, out=sys.stdout):
|
||||
def execute(self,
|
||||
args,
|
||||
show_usage=False,
|
||||
show_completions=False,
|
||||
out=sys.stdout):
|
||||
'''Parses `args` and invokes the associated handler.
|
||||
|
||||
The handler is passed two `Arguments` objects with all arguments other
|
||||
|
@ -142,10 +148,11 @@ class ArgumentParser(object):
|
|||
if not show_completions:
|
||||
show_completions = any(a in self.complete_args for a in args)
|
||||
|
||||
all_global_args = set(a.lstrip('-/') for a in self.help_args | self.complete_args | self.global_args)
|
||||
all_global_args = set(
|
||||
a.lstrip('-/') for a in self.help_args | self.complete_args | self.global_args)
|
||||
def not_global(a):
|
||||
return a.lstrip('-/') not in all_global_args
|
||||
it = filter(not_global, args).__iter__()
|
||||
it = filter(not_global, args).__iter__() #pylint: disable=bad-builtin
|
||||
|
||||
m = self.noun_map
|
||||
nouns = []
|
||||
|
@ -161,17 +168,16 @@ class ArgumentParser(object):
|
|||
n = next(it, '')
|
||||
|
||||
try:
|
||||
expected_args = m['$args']
|
||||
expected_kwargs = m['$kwargs']
|
||||
handler = m['$handler']
|
||||
except LookupError:
|
||||
logger.debug('Missing data for noun %s', n)
|
||||
show_usage = True
|
||||
|
||||
|
||||
if show_completions:
|
||||
return self._display_completions(nouns, m, args, out)
|
||||
return ArgumentParser._display_completions(m, out)
|
||||
if show_usage:
|
||||
return self._display_usage(nouns, m, args, out)
|
||||
return self._display_usage(nouns, m, out)
|
||||
|
||||
parsed = Arguments()
|
||||
others = Arguments()
|
||||
|
@ -189,8 +195,9 @@ class ArgumentParser(object):
|
|||
elif target_value[1] is True:
|
||||
# Arg with no value
|
||||
if value is not None:
|
||||
print(_("argument '{0}' does not take a value").format(key_n), file=out)
|
||||
return self._display_usage(nouns, m, args, out)
|
||||
print(L("argument '{0}' does not take a value").format(key_n),
|
||||
file=out)
|
||||
return self._display_usage(nouns, m, out)
|
||||
parsed.add_from_dotted(target_value[0], True)
|
||||
else:
|
||||
# Arg with a value
|
||||
|
@ -208,16 +215,16 @@ class ArgumentParser(object):
|
|||
return handler(parsed, others)
|
||||
except IncorrectUsageError as ex:
|
||||
print(str(ex), file=out)
|
||||
return self.display_usage(nouns, m, args, out)
|
||||
return self._display_usage(nouns, m, out)
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
|
||||
def _display_usage(self, nouns, noun_map, arguments, out=sys.stdout):
|
||||
def _display_usage(self, nouns, noun_map, out=sys.stdout):
|
||||
spec = ' '.join(noun_map.get('$spec') or nouns)
|
||||
print(' {} {}'.format(self.prog, spec), file=out)
|
||||
print(file=out)
|
||||
out.flush()
|
||||
|
||||
|
||||
subnouns = sorted(k for k in noun_map if not k.startswith('$'))
|
||||
if subnouns:
|
||||
print('Subcommands', file=out)
|
||||
|
@ -225,7 +232,7 @@ class ArgumentParser(object):
|
|||
print(' {}'.format(n), file=out)
|
||||
print(file=out)
|
||||
out.flush()
|
||||
|
||||
|
||||
argdoc = noun_map.get('$argdoc')
|
||||
if argdoc:
|
||||
print('Arguments', file=out)
|
||||
|
@ -246,7 +253,8 @@ class ArgumentParser(object):
|
|||
out.flush()
|
||||
logger.debug('Expected documentation at %s', doc_file)
|
||||
|
||||
def _display_completions(self, nouns, noun_map, arguments, out=sys.stdout):
|
||||
@staticmethod
|
||||
def _display_completions(noun_map, out=sys.stdout):
|
||||
completions = [k for k in noun_map if not k.startswith('$')]
|
||||
|
||||
kwargs = noun_map.get('$kwargs')
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import os
|
||||
import os
|
||||
from ._logging import logger
|
||||
|
||||
DISABLE_VERIFY_VARIABLE_NAME = "AZURE_CLI_DISABLE_CONNECTION_VERIFICATION"
|
||||
|
||||
def allow_debug_connection(client):
|
||||
if should_disable_connection_verify():
|
||||
logger.warn("Connection verification disabled by environment variable %s", DISABLE_VERIFY_VARIABLE_NAME)
|
||||
def allow_debug_connection(client):
|
||||
if should_disable_connection_verify():
|
||||
logger.warning("Connection verification disabled by environment variable %s",
|
||||
DISABLE_VERIFY_VARIABLE_NAME)
|
||||
client.config.connection.verify = False
|
||||
|
||||
def should_disable_connection_verify():
|
||||
return bool(os.environ.get(DISABLE_VERIFY_VARIABLE_NAME))
|
||||
|
||||
def should_disable_connection_verify():
|
||||
return bool(os.environ.get(DISABLE_VERIFY_VARIABLE_NAME))
|
||||
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import os.path
|
||||
import os.path
|
||||
from codecs import open as codecs_open
|
||||
|
||||
from codecs import open
|
||||
_translations = dict()
|
||||
_locale_dir = ''
|
||||
|
||||
def L(key):
|
||||
return _translations.get(key) or '<NO_TRANSLATION:{}>'.format(key)
|
||||
|
||||
def install(locale_dir):
|
||||
mapping = []
|
||||
|
||||
with open(os.path.join(locale_dir, "messages.txt"), 'r', encoding='utf-8-sig') as f:
|
||||
|
||||
with codecs_open(os.path.join(locale_dir, "messages.txt"), 'r', encoding='utf-8-sig') as f:
|
||||
for i in f:
|
||||
if not i or i.startswith('#') or not i.strip():
|
||||
continue
|
||||
|
@ -13,18 +18,14 @@ def install(locale_dir):
|
|||
mapping.append((i[5:].strip(), None))
|
||||
else:
|
||||
mapping[-1] = (mapping[-1][0], i.strip())
|
||||
|
||||
translations = dict(mapping)
|
||||
def _(key):
|
||||
return translations.get(key) or '<NO_TRANSLATION:{}>'.format(key)
|
||||
_.locale_dir = locale_dir
|
||||
|
||||
__builtins__['_'] = _
|
||||
|
||||
globals()['_translations'] = dict(mapping)
|
||||
globals()['_locale_dir'] = locale_dir
|
||||
|
||||
def get_file(name):
|
||||
try:
|
||||
src = _.locale_dir
|
||||
src = _locale_dir
|
||||
except (NameError, AttributeError):
|
||||
raise RuntimeError("localizations not installed")
|
||||
|
||||
|
||||
return os.path.join(src, name)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import logging as _logging
|
||||
import logging as _logging
|
||||
import sys
|
||||
|
||||
__all__ = ['logging', 'configure_logging']
|
||||
__all__ = ['logger', 'configure_logging']
|
||||
|
||||
logger = _logging.Logger('az', _logging.WARNING)
|
||||
|
||||
|
@ -13,7 +13,7 @@ def _arg_name(arg):
|
|||
|
||||
def configure_logging(argv, config):
|
||||
level = _logging.WARNING
|
||||
|
||||
|
||||
# Load logging info from config
|
||||
if config.get('verbose'):
|
||||
level = _logging.INFO
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from __future__ import print_function, unicode_literals
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
@ -8,7 +8,7 @@ try:
|
|||
from io import StringIO
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from StringIO import StringIO
|
||||
from StringIO import StringIO #pylint: disable=import-error
|
||||
|
||||
class OutputFormatException(Exception):
|
||||
pass
|
||||
|
@ -40,9 +40,9 @@ def format_text(obj):
|
|||
except TypeError:
|
||||
return ''
|
||||
|
||||
class OutputProducer(object):
|
||||
|
||||
def __init__(self, formatter=format_json, file=sys.stdout):
|
||||
class OutputProducer(object): #pylint: disable=too-few-public-methods
|
||||
|
||||
def __init__(self, formatter=format_json, file=sys.stdout): #pylint: disable=redefined-builtin
|
||||
self.formatter = formatter
|
||||
self.file = file
|
||||
|
||||
|
@ -58,7 +58,7 @@ class TableOutput(object):
|
|||
def dump(self):
|
||||
if len(self._rows) == 1:
|
||||
return
|
||||
|
||||
|
||||
with StringIO() as io:
|
||||
cols = [(c, self._columns[c]) for c in self._column_order]
|
||||
io.write(' | '.join(c.center(w) for c, w in cols))
|
||||
|
@ -91,7 +91,7 @@ class TextOutput(object):
|
|||
|
||||
def __init__(self):
|
||||
self.identifiers = {}
|
||||
|
||||
|
||||
def add(self, identifier, value):
|
||||
if identifier in self.identifiers:
|
||||
self.identifiers[identifier].append(value)
|
||||
|
@ -100,14 +100,14 @@ class TextOutput(object):
|
|||
|
||||
def dump(self):
|
||||
with StringIO() as io:
|
||||
for id in sorted(self.identifiers):
|
||||
io.write(id.upper())
|
||||
for identifier in sorted(self.identifiers):
|
||||
io.write(identifier.upper())
|
||||
io.write('\t')
|
||||
for col in self.identifiers[id]:
|
||||
for col in self.identifiers[identifier]:
|
||||
if isinstance(col, str):
|
||||
io.write(col)
|
||||
else:
|
||||
# TODO: Handle complex objects
|
||||
# TODO: Need to handle complex objects
|
||||
io.write("null")
|
||||
io.write('\t')
|
||||
io.write('\n')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from msrest.authentication import BasicTokenAuthentication
|
||||
import collections
|
||||
from msrest.authentication import BasicTokenAuthentication
|
||||
from .main import CONFIG
|
||||
import collections
|
||||
|
||||
class Profile(object):
|
||||
|
||||
|
@ -37,10 +37,9 @@ class Profile(object):
|
|||
for s in subscriptions:
|
||||
s['active'] = False
|
||||
|
||||
if new_active_one:
|
||||
new_active_one['active'] = True
|
||||
else:
|
||||
new_subscriptions[0]['active'] = True
|
||||
if not new_active_one:
|
||||
new_active_one = new_subscriptions[0]
|
||||
new_active_one['active'] = True
|
||||
else:
|
||||
new_subscriptions[0]['active'] = True
|
||||
|
||||
|
@ -60,20 +59,20 @@ class Profile(object):
|
|||
raise ValueError('Please run "account set" to select active account.')
|
||||
|
||||
return BasicTokenAuthentication(
|
||||
{'access_token': active[0]['access_token']}), active[0]['id']
|
||||
{'access_token': active[0]['access_token']}), active[0]['id']
|
||||
|
||||
def set_active_subscription(self, subscription_id_or_name):
|
||||
subscriptions = self.load_subscriptions()
|
||||
|
||||
|
||||
subscription_id_or_name = subscription_id_or_name.lower()
|
||||
result = [x for x in subscriptions
|
||||
if subscription_id_or_name == x['id'].lower() or
|
||||
result = [x for x in subscriptions
|
||||
if subscription_id_or_name == x['id'].lower() or
|
||||
subscription_id_or_name == x['name'].lower()]
|
||||
|
||||
if len(result) != 1:
|
||||
raise ValueError('The subscription of "{}" does not exist or has more than'
|
||||
' one match.'.format(subscription_id_or_name))
|
||||
|
||||
|
||||
for s in subscriptions:
|
||||
s['active'] = False
|
||||
result[0]['active'] = True
|
||||
|
@ -91,7 +90,7 @@ class Profile(object):
|
|||
subscriptions[0]['active'] = True
|
||||
|
||||
self._save_subscriptions(subscriptions)
|
||||
|
||||
|
||||
def load_subscriptions(self):
|
||||
return self._storage.get('subscriptions') or []
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ except ImportError:
|
|||
import collections
|
||||
|
||||
|
||||
from codecs import open
|
||||
from codecs import open as codecs_open
|
||||
|
||||
class Session(collections.MutableMapping):
|
||||
'''A simple dict-like class that is backed by a JSON file.
|
||||
|
@ -28,14 +28,14 @@ class Session(collections.MutableMapping):
|
|||
st = os.stat(self.filename)
|
||||
if st.st_mtime + max_age < time.clock():
|
||||
self.save()
|
||||
with open(self.filename, 'r', encoding='utf-8-sig') as f:
|
||||
with codecs_open(self.filename, 'r', encoding='utf-8-sig') as f:
|
||||
self.data = json.load(f)
|
||||
except (OSError, IOError):
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
if self.filename:
|
||||
with open(self.filename, 'w', encoding='utf-8-sig') as f:
|
||||
with codecs_open(self.filename, 'w', encoding='utf-8-sig') as f:
|
||||
json.dump(self.data, f)
|
||||
|
||||
def save_with_retry(self, retries=5):
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
|
||||
def normalize_newlines(str_to_normalize):
|
||||
return str_to_normalize.replace('\r\n', '\n')
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
from .._argparse import IncorrectUsageError
|
||||
from .._argparse import IncorrectUsageError
|
||||
from .._logging import logger
|
||||
|
||||
# TODO: Alternatively, simply scan the directory for all modules
|
||||
COMMAND_MODULES = [
|
||||
'account',
|
||||
'login',
|
||||
'logout',
|
||||
'account',
|
||||
'network',
|
||||
'resourcegroup',
|
||||
'storage',
|
||||
'resourcegroup'
|
||||
'vm',
|
||||
]
|
||||
|
||||
_COMMANDS = {}
|
||||
|
@ -19,33 +21,33 @@ def command(name):
|
|||
return handler
|
||||
return add_command
|
||||
|
||||
def description(description):
|
||||
def description(description_text):
|
||||
def add_description(handler):
|
||||
_COMMANDS.setdefault(handler, {})['description'] = description
|
||||
logger.debug('Added description "%s" to %s', description, handler)
|
||||
_COMMANDS.setdefault(handler, {})['description'] = description_text
|
||||
logger.debug('Added description "%s" to %s', description_text, handler)
|
||||
return handler
|
||||
return add_description
|
||||
|
||||
def option(spec, description=None):
|
||||
def option(spec, description_text=None):
|
||||
def add_option(handler):
|
||||
_COMMANDS.setdefault(handler, {}).setdefault('args', []).append((spec, description))
|
||||
_COMMANDS.setdefault(handler, {}).setdefault('args', []).append((spec, description_text))
|
||||
logger.debug('Added option "%s" to %s', spec, handler)
|
||||
return handler
|
||||
return add_option
|
||||
|
||||
def add_to_parser(parser, command=None):
|
||||
def add_to_parser(parser, command_name=None):
|
||||
'''Loads commands into the parser
|
||||
|
||||
When `command` is specified, only commands from that module will be loaded.
|
||||
If the module is not found, all commands are loaded.
|
||||
'''
|
||||
|
||||
|
||||
# Importing the modules is sufficient to invoke the decorators. Then we can
|
||||
# get all of the commands from the _COMMANDS variable.
|
||||
loaded = False
|
||||
if command:
|
||||
if command_name:
|
||||
try:
|
||||
__import__('azure.cli.commands.' + command)
|
||||
__import__('azure.cli.commands.' + command_name)
|
||||
loaded = True
|
||||
except ImportError:
|
||||
# Unknown command - we'll load all below
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import inspect
|
||||
from msrest import Serializer
|
||||
from ..commands import command, description, option
|
||||
from azure.cli._argparse import IncorrectUsageError
|
||||
|
||||
def _decorate_command(name, func):
|
||||
return command(name)(func)
|
||||
|
||||
def _decorate_description(desc, func):
|
||||
return description(desc)(func)
|
||||
|
||||
def _decorate_option(spec, descr, func):
|
||||
return option(spec, descr)(func)
|
||||
|
||||
def _make_func(client_factory, member_name, return_type_name, unbound_func):
|
||||
def call_client(args, unexpected): #pylint: disable=unused-argument
|
||||
client = client_factory()
|
||||
ops_instance = getattr(client, member_name)
|
||||
try:
|
||||
result = unbound_func(ops_instance, **args)
|
||||
if not return_type_name:
|
||||
return {}
|
||||
return Serializer().serialize_data(result, return_type_name)
|
||||
except TypeError as exception:
|
||||
# TODO: Evaluate required/missing parameters and provide specific
|
||||
# usage for missing params...
|
||||
raise IncorrectUsageError(exception)
|
||||
|
||||
return call_client
|
||||
|
||||
def _option_description(operation, arg):
|
||||
"""Pull out parameter help from doccomments of the command
|
||||
"""
|
||||
# TODO: We are currently doing this for every option/argument.
|
||||
# We should do it (at most) once for a given command...
|
||||
return ' '.join(l.split(':')[-1] for l in inspect.getdoc(operation).splitlines()
|
||||
if l.startswith(':param') and arg + ':' in l)
|
||||
|
||||
EXCLUDED_PARAMS = frozenset(['self', 'raw', 'custom_headers', 'operation_config'])
|
||||
|
||||
def operation_builder(package_name, resource_type, member_name, client_type, operations):
|
||||
for operation, return_type_name in operations:
|
||||
opname = operation.__name__
|
||||
func = _make_func(client_type, member_name, return_type_name, operation)
|
||||
func = _decorate_command(' '.join([package_name, resource_type, opname]), func)
|
||||
|
||||
args = []
|
||||
try:
|
||||
# only supported in python3 - falling back to argspec if not available
|
||||
sig = inspect.signature(operation)
|
||||
args = sig.parameters
|
||||
except AttributeError:
|
||||
sig = inspect.getargspec(operation) #pylint: disable=deprecated-method
|
||||
args = sig.args
|
||||
|
||||
for arg in [a for a in args if not a in EXCLUDED_PARAMS]:
|
||||
spec = '--%s <%s>' % (arg, arg)
|
||||
func = _decorate_option(spec, _option_description(operation, arg), func=func)
|
|
@ -1,10 +1,10 @@
|
|||
from .._profile import Profile
|
||||
from .._profile import Profile
|
||||
import azure.cli._debug as _debug
|
||||
import azure.cli as cli
|
||||
|
||||
def get_service_client(client_type, config_type):
|
||||
profile = Profile()
|
||||
client = client_type(config_type(*profile.get_login_credentials()))
|
||||
_debug.allow_debug_connection(client)
|
||||
_debug.allow_debug_connection(client)
|
||||
client.config.add_user_agent("AZURECLI_{}".format(cli.__version__))
|
||||
return client
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
from .._profile import Profile
|
||||
from ..commands import command, description, option
|
||||
from .._locale import L
|
||||
|
||||
@command('account list')
|
||||
@description(_('List the imported subscriptions.'))
|
||||
def list_subscriptions(args, unexpected):
|
||||
@description(L('List the imported subscriptions.'))
|
||||
def list_subscriptions(args, unexpected): #pylint: disable=unused-argument
|
||||
profile = Profile()
|
||||
subscriptions = profile.load_subscriptions()
|
||||
|
||||
return subscriptions
|
||||
|
||||
@command('account set')
|
||||
@description(_('Set the current subscription'))
|
||||
@option('--subscription-id -n <subscription-id>', _('Subscription Id, unique name also works.'))
|
||||
def set_active_subscription(args, unexpected):
|
||||
id = args.get('subscription-id')
|
||||
@description(L('Set the current subscription'))
|
||||
@option('--subscription-id -n <subscription-id>', L('Subscription Id, unique name also works.'))
|
||||
def set_active_subscription(args, unexpected): #pylint: disable=unused-argument
|
||||
subscription_id = args.get('subscription-id')
|
||||
if not id:
|
||||
raise ValueError(_('Please provide subscription id or unique name.'))
|
||||
raise ValueError(L('Please provide subscription id or unique name.'))
|
||||
|
||||
profile = Profile()
|
||||
profile.set_active_subscription(id)
|
||||
profile.set_active_subscription(subscription_id)
|
||||
|
|
|
@ -1,37 +1,40 @@
|
|||
from msrestazure.azure_active_directory import UserPassCredentials
|
||||
from msrest import Serializer
|
||||
from msrestazure.azure_active_directory import UserPassCredentials
|
||||
from azure.mgmt.resource.subscriptions import SubscriptionClient, \
|
||||
SubscriptionClientConfiguration
|
||||
|
||||
from msrest import Serializer
|
||||
|
||||
from .._profile import Profile
|
||||
from ..commands import command, description, option
|
||||
from .._debug import should_disable_connection_verify
|
||||
from .._locale import L
|
||||
|
||||
CLIENT_ID = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'
|
||||
|
||||
@command('login')
|
||||
@description(_('log in to an Azure subscription using Active Directory Organization Id'))
|
||||
@option('--username -u <username>', _('organization Id. Microsoft Account is not yet supported.'))
|
||||
@option('--password -p <password>', _('user password, will prompt if not given.'))
|
||||
def login(args, unexpected):
|
||||
@description(L('log in to an Azure subscription using Active Directory Organization Id'))
|
||||
@option('--username -u <username>', L('organization Id. Microsoft Account is not yet supported.'))
|
||||
@option('--password -p <password>', L('user password, will prompt if not given.'))
|
||||
def login(args, unexpected): #pylint: disable=unused-argument
|
||||
username = args.get('username')
|
||||
|
||||
password = args.get('password')
|
||||
if not password:
|
||||
import getpass
|
||||
password = getpass.getpass(_('Password: '))
|
||||
password = getpass.getpass(L('Password: '))
|
||||
|
||||
credentials = UserPassCredentials(username, password, client_id=CLIENT_ID, verify=not should_disable_connection_verify())
|
||||
credentials = UserPassCredentials(username,
|
||||
password,
|
||||
client_id=CLIENT_ID,
|
||||
verify=not should_disable_connection_verify())
|
||||
client = SubscriptionClient(SubscriptionClientConfiguration(credentials))
|
||||
subscriptions = client.subscriptions.list()
|
||||
|
||||
if not subscriptions:
|
||||
raise RuntimeError(_('No subscriptions found for this account.'))
|
||||
raise RuntimeError(L('No subscriptions found for this account.'))
|
||||
|
||||
serializable = Serializer().serialize_data(subscriptions, "[Subscription]")
|
||||
|
||||
#keep useful properties and not json serializable
|
||||
#keep useful properties and not json serializable
|
||||
profile = Profile()
|
||||
consolidated = Profile.normalize_properties(username, subscriptions)
|
||||
profile.set_subscriptions(consolidated, credentials.token['access_token'])
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
from .._profile import Profile
|
||||
from ..commands import command, description, option
|
||||
from .._locale import L
|
||||
|
||||
@command('logout')
|
||||
@description(_('Log out from Azure subscription using Active Directory.'))
|
||||
@option('--username -u <username>', _('User name used to log out from Azure Active Directory.'))
|
||||
def logout(args, unexpected):
|
||||
@description(L('Log out from Azure subscription using Active Directory.'))
|
||||
@option('--username -u <username>', L('User name used to log out from Azure Active Directory.'))
|
||||
def logout(args, unexpected): #pylint: disable=unused-argument
|
||||
username = args.get('username')
|
||||
if not username:
|
||||
raise ValueError(_('Please provide a valid username to logout.'))
|
||||
raise ValueError(L('Please provide a valid username to logout.'))
|
||||
|
||||
profile = Profile()
|
||||
profile.logout(username)
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
from azure.mgmt.network import NetworkManagementClient, NetworkManagementClientConfiguration
|
||||
from azure.mgmt.network.operations import (ApplicationGatewaysOperations,
|
||||
ExpressRouteCircuitAuthorizationsOperations,
|
||||
ExpressRouteCircuitPeeringsOperations,
|
||||
ExpressRouteCircuitsOperations,
|
||||
ExpressRouteServiceProvidersOperations,
|
||||
LoadBalancersOperations,
|
||||
LocalNetworkGatewaysOperations,
|
||||
NetworkInterfacesOperations,
|
||||
NetworkSecurityGroupsOperations,
|
||||
PublicIPAddressesOperations,
|
||||
RouteTablesOperations,
|
||||
RoutesOperations,
|
||||
SecurityRulesOperations,
|
||||
SubnetsOperations,
|
||||
UsagesOperations,
|
||||
VirtualNetworkGatewayConnectionsOperations,
|
||||
VirtualNetworkGatewaysOperations,
|
||||
VirtualNetworksOperations)
|
||||
|
||||
from ._command_creation import get_service_client
|
||||
from ..commands import _auto_command
|
||||
|
||||
def _network_client_factory():
|
||||
return get_service_client(NetworkManagementClient, NetworkManagementClientConfiguration)
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
# Application gateways
|
||||
_auto_command.operation_builder("network",
|
||||
"appgateway",
|
||||
"application_gateways",
|
||||
_network_client_factory,
|
||||
[
|
||||
(ApplicationGatewaysOperations.delete, None),
|
||||
(ApplicationGatewaysOperations.get, 'ApplicationGateway'),
|
||||
(ApplicationGatewaysOperations.list, '[ApplicationGateway]'),
|
||||
(ApplicationGatewaysOperations.list_all, '[ApplicationGateway]'),
|
||||
(ApplicationGatewaysOperations.start, None),
|
||||
(ApplicationGatewaysOperations.stop, None),
|
||||
])
|
||||
|
||||
# ExpressRouteCircuitAuthorizationsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"expressroutecircuitauth",
|
||||
"express_route_circuit_authorizations",
|
||||
_network_client_factory,
|
||||
[
|
||||
(ExpressRouteCircuitAuthorizationsOperations.delete, None),
|
||||
(ExpressRouteCircuitAuthorizationsOperations.get, 'ExpressRouteCircuitAuthorization'),
|
||||
(ExpressRouteCircuitAuthorizationsOperations.list, '[ExpressRouteCircuitAuthorization]'),
|
||||
])
|
||||
|
||||
# ExpressRouteCircuitPeeringsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"expressroutecircuitpeering",
|
||||
"express_route_circuit_peerings",
|
||||
_network_client_factory,
|
||||
[
|
||||
(ExpressRouteCircuitPeeringsOperations.delete, None),
|
||||
(ExpressRouteCircuitPeeringsOperations.get, 'ExpressRouteCircuitPeering'),
|
||||
(ExpressRouteCircuitPeeringsOperations.list, '[ExpressRouteCircuitPeering]'),
|
||||
])
|
||||
|
||||
# ExpressRouteCircuitsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"expressroutecircuit",
|
||||
"express_route_circuits",
|
||||
_network_client_factory,
|
||||
[
|
||||
(ExpressRouteCircuitsOperations.delete, None),
|
||||
(ExpressRouteCircuitsOperations.get, 'ExpressRouteCircuit'),
|
||||
(ExpressRouteCircuitsOperations.list_arp_table, '[ExpressRouteCircuitArpTable]'),
|
||||
(ExpressRouteCircuitsOperations.list_routes_table, '[ExpressRouteCircuitRoutesTable]'),
|
||||
(ExpressRouteCircuitsOperations.list_stats, '[ExpressRouteCircuitStats]'),
|
||||
(ExpressRouteCircuitsOperations.list, '[ExpressRouteCircuit]'),
|
||||
(ExpressRouteCircuitsOperations.list_all, '[ExpressRouteCircuit]'),
|
||||
])
|
||||
|
||||
# ExpressRouteServiceProvidersOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"expressroutesp",
|
||||
"express_route_service_providers",
|
||||
_network_client_factory,
|
||||
[
|
||||
(ExpressRouteServiceProvidersOperations.list, '[ExpressRouteServiceProvider]'),
|
||||
])
|
||||
|
||||
# LoadBalancersOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"lb",
|
||||
"load_balancers",
|
||||
_network_client_factory,
|
||||
[
|
||||
(LoadBalancersOperations.delete, None),
|
||||
(LoadBalancersOperations.get, 'LoadBalancer'),
|
||||
(LoadBalancersOperations.list_all, '[LoadBalancer]'),
|
||||
(LoadBalancersOperations.list, '[LoadBalancer]'),
|
||||
])
|
||||
|
||||
# LocalNetworkGatewaysOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"localgateways",
|
||||
"local_network_gateways",
|
||||
_network_client_factory,
|
||||
[
|
||||
(LocalNetworkGatewaysOperations.get, 'LocalNetworkGateway'),
|
||||
(LocalNetworkGatewaysOperations.delete, None),
|
||||
(LocalNetworkGatewaysOperations.list, '[LocalNetworkGateway]'),
|
||||
])
|
||||
|
||||
|
||||
# NetworkInterfacesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"nic",
|
||||
"network_interfaces",
|
||||
_network_client_factory,
|
||||
[
|
||||
(NetworkInterfacesOperations.delete, None),
|
||||
(NetworkInterfacesOperations.get, 'NetworkInterface'),
|
||||
(NetworkInterfacesOperations.list_virtual_machine_scale_set_vm_network_interfaces, '[NetworkInterface]'),
|
||||
(NetworkInterfacesOperations.list_virtual_machine_scale_set_network_interfaces, '[NetworkInterface]'),
|
||||
(NetworkInterfacesOperations.get_virtual_machine_scale_set_network_interface, 'NetworkInterface'),
|
||||
(NetworkInterfacesOperations.list_all, '[NetworkInterface]'),
|
||||
(NetworkInterfacesOperations.list, '[NetworkInterface]'),
|
||||
])
|
||||
|
||||
# NetworkSecurityGroupsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"securitygroup",
|
||||
"network_security_groups",
|
||||
_network_client_factory,
|
||||
[
|
||||
(NetworkSecurityGroupsOperations.delete, None),
|
||||
(NetworkSecurityGroupsOperations.delete, 'NetworkSecurityGroup'),
|
||||
(NetworkSecurityGroupsOperations.list_all, '[NetworkSecurityGroup]'),
|
||||
(NetworkSecurityGroupsOperations.list, '[NetworkSecurityGroup]'),
|
||||
])
|
||||
|
||||
# PublicIPAddressesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"publicipaddress",
|
||||
"public_ip_addresses",
|
||||
_network_client_factory,
|
||||
[
|
||||
(PublicIPAddressesOperations.delete, None),
|
||||
(PublicIPAddressesOperations.get, 'PublicIPAddress'),
|
||||
(PublicIPAddressesOperations.list_all, '[PublicIPAddress]'),
|
||||
(PublicIPAddressesOperations.list, '[PublicIPAddress]'),
|
||||
])
|
||||
|
||||
# RouteTablesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"routetable",
|
||||
"route_tables",
|
||||
_network_client_factory,
|
||||
[
|
||||
(RouteTablesOperations.delete, None),
|
||||
(RouteTablesOperations.get, 'RouteTable'),
|
||||
(RouteTablesOperations.list, '[RouteTable]'),
|
||||
(RouteTablesOperations.list_all, '[RouteTable]'),
|
||||
])
|
||||
|
||||
# RoutesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"routeoperation",
|
||||
"routes",
|
||||
_network_client_factory,
|
||||
[
|
||||
(RoutesOperations.delete, None),
|
||||
(RoutesOperations.get, 'Route'),
|
||||
(RoutesOperations.list, '[Route]'),
|
||||
])
|
||||
|
||||
# SecurityRulesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"securityrules",
|
||||
"security_rules",
|
||||
_network_client_factory,
|
||||
[
|
||||
(SecurityRulesOperations.delete, None),
|
||||
(SecurityRulesOperations.get, 'SecurityRule'),
|
||||
(SecurityRulesOperations.list, '[SecurityRule]'),
|
||||
])
|
||||
|
||||
# SubnetsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"subnet",
|
||||
"subnets",
|
||||
_network_client_factory,
|
||||
[
|
||||
(SubnetsOperations.delete, None),
|
||||
(SubnetsOperations.get, 'Subnet'),
|
||||
(SubnetsOperations.list, '[Subnet]'),
|
||||
])
|
||||
|
||||
# UsagesOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"usage",
|
||||
"usages",
|
||||
_network_client_factory,
|
||||
[
|
||||
(UsagesOperations.list, '[Usage]'),
|
||||
])
|
||||
|
||||
# VirtualNetworkGatewayConnectionsOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"vnetgatewayconnection",
|
||||
"virtual_network_gateway_connections",
|
||||
_network_client_factory,
|
||||
[
|
||||
(VirtualNetworkGatewayConnectionsOperations.delete, None),
|
||||
(VirtualNetworkGatewayConnectionsOperations.get, 'VirtualNetworkGatewayConnection'),
|
||||
(VirtualNetworkGatewayConnectionsOperations.get_shared_key, 'ConnectionSharedKeyResult'),
|
||||
(VirtualNetworkGatewayConnectionsOperations.list, '[VirtualNetworkGatewayConnection]'),
|
||||
(VirtualNetworkGatewayConnectionsOperations.reset_shared_key, 'ConnectionResetSharedKey'),
|
||||
(VirtualNetworkGatewayConnectionsOperations.set_shared_key, 'ConnectionSharedKey'),
|
||||
])
|
||||
|
||||
# VirtualNetworkGatewaysOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"vnetgateway",
|
||||
"virtual_network_gateways",
|
||||
_network_client_factory,
|
||||
[
|
||||
(VirtualNetworkGatewaysOperations.delete, None),
|
||||
(VirtualNetworkGatewaysOperations.get, 'VirtualNetworkGateway'),
|
||||
(VirtualNetworkGatewaysOperations.list, '[VirtualNetworkGateway]'),
|
||||
(VirtualNetworkGatewaysOperations.reset, 'VirtualNetworkGateway'),
|
||||
])
|
||||
|
||||
# VirtualNetworksOperations
|
||||
_auto_command.operation_builder("network",
|
||||
"vnet",
|
||||
"virtual_networks",
|
||||
_network_client_factory,
|
||||
[
|
||||
(VirtualNetworksOperations.delete, None),
|
||||
(VirtualNetworksOperations.get, 'VirtualNetwork'),
|
||||
(VirtualNetworksOperations.list, '[VirtualNetwork]'),
|
||||
(VirtualNetworksOperations.list_all, '[VirtualNetwork]'),
|
||||
])
|
|
@ -1,24 +1,24 @@
|
|||
from msrest import Serializer
|
||||
|
||||
from ..commands import command, description, option
|
||||
from ..commands import command, description
|
||||
from .._profile import Profile
|
||||
|
||||
@command('resource group list')
|
||||
@description('List resource groups')
|
||||
# TODO: waiting on Python Azure SDK bug fixes
|
||||
#@option('--tag-name -g <tagName>', _("the resource group's tag name"))
|
||||
#@option('--tag-value -g <tagValue>', _("the resource group's tag value"))
|
||||
#@option('--top -g <number>', _("Top N resource groups to retrieve"))
|
||||
def list_groups(args, unexpected):
|
||||
from azure.mgmt.resource.resources import ResourceManagementClient, ResourceManagementClientConfiguration
|
||||
# @option('--tag-name -g <tagName>', L('the resource group's tag name'))
|
||||
# @option('--tag-value -g <tagValue>', L('the resource group's tag value'))
|
||||
# @option('--top -g <number>', L('Top N resource groups to retrieve'))
|
||||
def list_groups(args, unexpected): #pylint: disable=unused-argument
|
||||
from azure.mgmt.resource.resources import ResourceManagementClient, \
|
||||
ResourceManagementClientConfiguration
|
||||
from azure.mgmt.resource.resources.models import ResourceGroup, ResourceGroupFilter
|
||||
|
||||
rmc = ResourceManagementClient(ResourceManagementClientConfiguration(*Profile().get_login_credentials()))
|
||||
rmc = ResourceManagementClient(
|
||||
ResourceManagementClientConfiguration(*Profile().get_login_credentials()))
|
||||
|
||||
# TODO: waiting on Python Azure SDK bug fixes
|
||||
#group_filter = ResourceGroupFilter(args.get('tag-name'), args.get('tag-value'))
|
||||
#groups = rmc.resource_groups.list(filter=None, top=args.get('top'))
|
||||
groups = rmc.resource_groups.list()
|
||||
|
||||
serializable = Serializer().serialize_data(groups, "[ResourceGroup]")
|
||||
return serializable
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
from msrest import Serializer
|
||||
|
||||
from ..main import SESSION
|
||||
from msrest import Serializer
|
||||
from ..commands import command, description, option
|
||||
from ._command_creation import get_service_client
|
||||
from .._logging import logger
|
||||
from .._locale import L
|
||||
|
||||
@command('storage account list')
|
||||
@description(_('List storage accounts'))
|
||||
@option('--resource-group -g <resourceGroup>', _('the resource group name'))
|
||||
@option('--subscription -s <id>', _('the subscription id'))
|
||||
def list_accounts(args, unexpected):
|
||||
@description(L('List storage accounts'))
|
||||
@option('--resource-group -g <resourceGroup>', L('the resource group name'))
|
||||
@option('--subscription -s <id>', L('the subscription id'))
|
||||
def list_accounts(args, unexpected): #pylint: disable=unused-argument
|
||||
from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration
|
||||
from azure.mgmt.storage.models import StorageAccount
|
||||
from msrestazure.azure_active_directory import UserPassCredentials
|
||||
|
@ -26,10 +26,7 @@ def list_accounts(args, unexpected):
|
|||
|
||||
@command('storage account check')
|
||||
@option('--account-name <name>')
|
||||
def checkname(args, unexpected):
|
||||
def checkname(args, unexpected): #pylint: disable=unused-argument
|
||||
from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration
|
||||
|
||||
smc = get_service_client(StorageManagementClient, StorageManagementClientConfiguration)
|
||||
logger.warn(smc.storage_accounts.check_name_availability(args.account_name))
|
||||
|
||||
|
||||
logger.warning(smc.storage_accounts.check_name_availability(args.account_name))
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
from azure.mgmt.compute import ComputeManagementClient, ComputeManagementClientConfiguration
|
||||
from azure.mgmt.compute.operations import (AvailabilitySetsOperations,
|
||||
VirtualMachineExtensionImagesOperations,
|
||||
VirtualMachineExtensionsOperations,
|
||||
VirtualMachineImagesOperations,
|
||||
UsageOperations,
|
||||
VirtualMachineSizesOperations,
|
||||
VirtualMachinesOperations,
|
||||
VirtualMachineScaleSetsOperations,
|
||||
VirtualMachineScaleSetVMsOperations)
|
||||
|
||||
from ._command_creation import get_service_client
|
||||
from ..commands import _auto_command
|
||||
|
||||
def _compute_client_factory():
|
||||
return get_service_client(ComputeManagementClient, ComputeManagementClientConfiguration)
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
_auto_command.operation_builder("vm",
|
||||
"availabilityset",
|
||||
"availability_sets",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(AvailabilitySetsOperations.delete, None),
|
||||
(AvailabilitySetsOperations.get, 'AvailabilitySet'),
|
||||
(AvailabilitySetsOperations.list, '[AvailabilitySet]'),
|
||||
(AvailabilitySetsOperations.list_available_sizes, '[VirtualMachineSize]')
|
||||
])
|
||||
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"machineextensionimages",
|
||||
"virtual_machine_extension_images",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineExtensionImagesOperations.get, 'VirtualMachineExtensionImage'),
|
||||
(VirtualMachineExtensionImagesOperations.list_types, '[VirtualMachineImageResource]'),
|
||||
(VirtualMachineExtensionImagesOperations.list_versions, '[VirtualMachineImageResource]'),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"extensions",
|
||||
"virtual_machine_extensions",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineExtensionsOperations.delete, None),
|
||||
(VirtualMachineExtensionsOperations.get, 'VirtualMachineExtension'),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"image",
|
||||
"virtual_machine_images",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineImagesOperations.get, 'VirtualMachineImage'),
|
||||
(VirtualMachineImagesOperations.list, '[VirtualMachineImageResource]'),
|
||||
(VirtualMachineImagesOperations.list_offers, '[VirtualMachineImageResource]'),
|
||||
(VirtualMachineImagesOperations.list_publishers, '[VirtualMachineImageResource]'),
|
||||
(VirtualMachineImagesOperations.list_skus, '[VirtualMachineImageResource]'),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"usage",
|
||||
"usage",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(UsageOperations.list, '[Usage]'),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"size",
|
||||
"virtual_machine_sizes",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineSizesOperations.list, '[VirtualMachineSize]'),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"",
|
||||
"virtual_machines",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachinesOperations.delete, None),
|
||||
(VirtualMachinesOperations.deallocate, None),
|
||||
(VirtualMachinesOperations.generalize, None),
|
||||
(VirtualMachinesOperations.get, 'VirtualMachine'),
|
||||
(VirtualMachinesOperations.list, '[VirtualMachine]'),
|
||||
(VirtualMachinesOperations.list_all, '[VirtualMachine]'),
|
||||
(VirtualMachinesOperations.list_available_sizes, '[VirtualMachineSize]'),
|
||||
(VirtualMachinesOperations.power_off, None),
|
||||
(VirtualMachinesOperations.restart, None),
|
||||
(VirtualMachinesOperations.start, None),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"scaleset",
|
||||
"virtual_machine_scale_sets",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineScaleSetsOperations.deallocate, None),
|
||||
(VirtualMachineScaleSetsOperations.delete, None),
|
||||
(VirtualMachineScaleSetsOperations.get, 'VirtualMachineScaleSet'),
|
||||
(VirtualMachineScaleSetsOperations.delete_instances, None),
|
||||
(VirtualMachineScaleSetsOperations.get_instance_view, 'VirtualMachineScaleSetInstanceView'),
|
||||
(VirtualMachineScaleSetsOperations.list, '[VirtualMachineScaleSet]'),
|
||||
(VirtualMachineScaleSetsOperations.list_all, '[VirtualMachineScaleSet]'),
|
||||
(VirtualMachineScaleSetsOperations.list_skus, '[VirtualMachineScaleSet]'),
|
||||
(VirtualMachineScaleSetsOperations.power_off, None),
|
||||
(VirtualMachineScaleSetsOperations.restart, None),
|
||||
(VirtualMachineScaleSetsOperations.start, None),
|
||||
(VirtualMachineScaleSetsOperations.update_instances, None),
|
||||
])
|
||||
|
||||
_auto_command.operation_builder("vm",
|
||||
"vmscaleset",
|
||||
"virtual_machine_scale_set_vms",
|
||||
_compute_client_factory,
|
||||
[
|
||||
(VirtualMachineScaleSetVMsOperations.deallocate, None),
|
||||
(VirtualMachineScaleSetVMsOperations.delete, None),
|
||||
(VirtualMachineScaleSetVMsOperations.get, None),
|
||||
(VirtualMachineScaleSetVMsOperations.get_instance_view, 'VirtualMachineScaleSetVMInstanceView'),
|
||||
(VirtualMachineScaleSetVMsOperations.list, '[VirtualMachineScaleSetVM]'),
|
||||
(VirtualMachineScaleSetVMsOperations.power_off, None),
|
||||
(VirtualMachineScaleSetVMsOperations.restart, None),
|
||||
(VirtualMachineScaleSetVMsOperations.start, None),
|
||||
])
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
import os
|
||||
|
||||
from ._argparse import ArgumentParser
|
||||
from ._locale import install as locale_install
|
||||
from ._logging import configure_logging, logger
|
||||
from ._session import Session
|
||||
from ._output import OutputProducer
|
||||
|
@ -12,17 +11,18 @@ CONFIG = Session()
|
|||
# SESSION provides read-write session variables
|
||||
SESSION = Session()
|
||||
|
||||
# Load the user's preferred locale from their configuration
|
||||
LOCALE = CONFIG.get('locale', 'en-US')
|
||||
locale_install(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'locale', LOCALE))
|
||||
|
||||
|
||||
def main(args):
|
||||
CONFIG.load(os.path.expanduser('~/az.json'))
|
||||
SESSION.load(os.path.expanduser('~/az.sess'), max_age=3600)
|
||||
|
||||
configure_logging(args, CONFIG)
|
||||
|
||||
from ._locale import install as locale_install
|
||||
locale_install(os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'locale',
|
||||
CONFIG.get('locale', 'en-US')))
|
||||
|
||||
|
||||
parser = ArgumentParser("az")
|
||||
|
||||
import azure.cli.commands as commands
|
||||
|
@ -36,7 +36,7 @@ def main(args):
|
|||
else:
|
||||
# No noun found, so load all commands.
|
||||
commands.add_to_parser(parser)
|
||||
|
||||
|
||||
try:
|
||||
result = parser.execute(args)
|
||||
# Commands can return a dictionary/list of results
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
import logging
|
||||
import unittest
|
||||
|
||||
from azure.cli.commands._auto_command import (_decorate_command,
|
||||
_decorate_option)
|
||||
|
||||
from azure.cli.commands import _COMMANDS
|
||||
|
||||
class Test_autocommand(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Ensure initialization has occurred correctly
|
||||
import azure.cli.main
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
logging.shutdown()
|
||||
|
||||
def test_raw_register_command(self):
|
||||
command_name = 'da command'
|
||||
def testfunc():
|
||||
return testfunc
|
||||
|
||||
# Run test code
|
||||
_decorate_command(command_name, testfunc)
|
||||
|
||||
# Verify
|
||||
registered_command = _COMMANDS.get(testfunc, None)
|
||||
self.assertIsNotNone(registered_command)
|
||||
self.assertFalse('args' in registered_command.keys())
|
||||
self.assertEqual(registered_command['name'], command_name)
|
||||
|
||||
def test_raw_register_command_with_one_option(self):
|
||||
command_name = 'da command with one arg'
|
||||
def testfunc():
|
||||
return testfunc
|
||||
|
||||
# Run test code
|
||||
func = _decorate_command(command_name, testfunc)
|
||||
spec = '--tre <tre>'
|
||||
desc = 'Kronor'
|
||||
func = _decorate_option(spec, desc, func)
|
||||
|
||||
# Verify
|
||||
registered_command = _COMMANDS.get(testfunc, None)
|
||||
self.assertIsNotNone(registered_command)
|
||||
self.assertEqual(registered_command['name'], command_name)
|
||||
self.assertEqual(len(registered_command['args']), 1)
|
||||
self.assertEqual(registered_command['args'][0], (spec, desc))
|
||||
|
||||
def test_load_test_commands(self):
|
||||
import sys
|
||||
from azure.cli._argparse import ArgumentParser
|
||||
from azure.cli.commands import add_to_parser
|
||||
|
||||
# sneaky trick to avoid loading any command modules...
|
||||
sys.modules['azure.cli.commands.test'] = sys
|
||||
|
||||
command_name = 'da command with one arg and unexpected'
|
||||
def testfunc(args, _):
|
||||
# Check that the argument passing actually works...
|
||||
self.assertEqual(args['tre'], 'wombat')
|
||||
return testfunc
|
||||
|
||||
# Run test code
|
||||
func = _decorate_command(command_name, testfunc)
|
||||
spec = '--tre <tre>'
|
||||
desc = 'Kronor'
|
||||
func = _decorate_option(spec, desc, func)
|
||||
|
||||
p = ArgumentParser('automcommandtest')
|
||||
add_to_parser(p, 'test')
|
||||
|
||||
result = p.execute(command_name.split(' ') + '--tre wombat'.split(' '))
|
||||
self.assertEqual(result, func)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Загрузка…
Ссылка в новой задаче