Init with new python client runtime.

This is a combination of 21 commits.
Removed @property functions for now

Added some serialization tests

Removed function double-up

Changes to manager structure

Ignoring env

Prototype of hook structure

Early auth signing

Basic logging configuration

response status handling

Moved url formatting

Required to support "action" parameters (i.e. value-less query strings)

Changes to request structure

Beginning structure of azure runtime + AAD

Paging concept and lazy list deserialization

polling concept

Revisions to Polled class

Added attribute validation to serialization

Updated pool request models

Separated response models

Basic Azure service client

Moved msrest and msrestazure into package directory

Making sample operations more generic
This commit is contained in:
annatisch 2015-10-01 10:47:36 -07:00 коммит произвёл xingwu1
Родитель b43ac03103
Коммит 3aa5018b51
45 изменённых файлов: 3392 добавлений и 2079 удалений

66
.gitignore поставляемый
Просмотреть файл

@ -171,7 +171,71 @@ Thumbs.db
#old nuget restore folder
.nuget/
AutoRest/Generators/Ruby/*Tests/Gemfile.lock
AutoRest/Generators/Ruby/*/RspecTests/Generated/*
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
ClientRuntimes/Python/Python35-64-ENV/pip-selfcheck.json
ClientRuntimes/Python/Python35-64-ENV/pyvenv.cfg
ClientRuntimes/Python/Python35-64-ENV/Scripts/activate.bat
ClientRuntimes/Python/Python35-64-ENV/Scripts/Activate.ps1
ClientRuntimes/Python/Python35-64-ENV/Scripts/deactivate.bat
#dnx installation
dnx-clr-win-x86*/

Просмотреть файл

@ -6,15 +6,15 @@
<ProjectGuid>8523ba22-21d4-4f69-a73e-958b617c9d37</ProjectGuid>
<ProjectHome>
</ProjectHome>
<StartupFile>__init__.py</StartupFile>
<StartupFile>runtime/__init__.py</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<Name>clientruntime</Name>
<RootNamespace>client_runtime</RootNamespace>
<InterpreterId>{48d85c47-7987-4391-906e-d7b3fdb224c0}</InterpreterId>
<InterpreterVersion>2.7</InterpreterVersion>
<InterpreterId>{12c1f77c-3a20-4e2d-8df2-6f587311ea06}</InterpreterId>
<InterpreterVersion>3.5</InterpreterVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
@ -25,56 +25,86 @@
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<ItemGroup>
<Compile Include="msrest\adapter.py">
<Compile Include="runtime\msrestazure\aad.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\authentication.py">
<Compile Include="runtime\msrestazure\azure_configuration.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\configuration.py">
<Compile Include="runtime\msrestazure\azure_exceptions.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\exceptions.py">
<Compile Include="runtime\msrestazure\azure_handlers.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\hooks\logging.py">
<Compile Include="runtime\msrestazure\azure_resource.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\hooks\retry_policy.py">
<Compile Include="runtime\msrestazure\azure_response.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\logger.py">
<Compile Include="runtime\msrestazure\azure_service_client.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\request.py">
<Compile Include="runtime\msrestazure\__init__.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\response.py">
<Compile Include="runtime\msrest\adapter.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\serialization.py">
<Compile Include="runtime\msrest\authentication.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\service_client.py">
<Compile Include="runtime\msrest\configuration.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\test\__init__.py">
<Compile Include="runtime\msrest\exceptions.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="msrest\__init__.py">
<Compile Include="runtime\msrest\hooks.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="__init__.py" />
<Compile Include="runtime\msrest\handlers.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\logger.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\request.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\response.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\serialization.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\service_client.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\test\unittest_serialization.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\test\__init__.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\utils.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\msrest\__init__.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="runtime\__init__.py" />
</ItemGroup>
<ItemGroup>
<Folder Include="msrest\" />
<Folder Include="msrestazure\" />
<Folder Include="msrest\hooks\" />
<Folder Include="msrest\test\" />
<Folder Include="runtime\" />
<Folder Include="runtime\msrest\" />
<Folder Include="runtime\msrestazure\" />
<Folder Include="runtime\msrest\test\" />
</ItemGroup>
<ItemGroup>
<Interpreter Include="Python27-64-ENV\">
<Id>{48d85c47-7987-4391-906e-d7b3fdb224c0}</Id>
<Interpreter Include="..\..\..\PythonEnv\Python27-64-ENV\">
<Id>{5cdbe86c-f1f4-45a4-ad13-453be6b2cc3e}</Id>
<BaseInterpreter>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</BaseInterpreter>
<Version>2.7</Version>
<Description>Python27-64-ENV (Python 64-bit 2.7)</Description>
@ -84,6 +114,17 @@
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>Amd64</Architecture>
</Interpreter>
<Interpreter Include="..\..\..\PythonEnv\Python35-64-ENV\">
<Id>{12c1f77c-3a20-4e2d-8df2-6f587311ea06}</Id>
<BaseInterpreter>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</BaseInterpreter>
<Version>3.5</Version>
<Description>Python35-64-ENV (Python 64-bit 3.5)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>Amd64</Architecture>
</Interpreter>
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

Просмотреть файл

@ -1,25 +0,0 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------

Просмотреть файл

@ -1,25 +0,0 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------

Просмотреть файл

@ -1,25 +0,0 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------

Просмотреть файл

@ -1,160 +0,0 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from response import HTTPResponse
import json
class Serialized(object):
def __init__(self, request_obj):
self.request = request_obj
self.serialize_type = {
'datetime':self.serialize_time,
'duration':self.serialize_duration,
'complex':self.serialize_object,
'[]':self.serialize_iter,
'{}':self.serialize_dict
# etc
}
def __getattr__(self, attr):
orig_attr = self.request.__getattribute__(attr)
attr_type = self.request.attribute_map[attr]['type']
if orig_attr is None or attr_type in ['str', 'int']:
return orig_attr
if attr_type in self.serialize_type:
return self.serialize_type[attr_type](orig_attr)
iter_type = attr_type[0] + attr_type[-1]
if iter_type in self.serialize_type:
return self.serialize_type[iter_type](orig_attr, attr_type[1,-1])
return self.serialize_object(orig_attr)
def __call__(self):
serialized = {}
for attr in self.request.attribute_map:
serialized[self.request.attribute_map[attr]['key']] = self.attr
return serialized
def serilize_object(self, cmplx_obj):
serialized = Serialized(cmplx_obj)
return serialized()
def serialize_time(self, attr):
return str(attr)
def serialize_iter(self, attr, iter_type):
if iter_type in ['str','int']:
return attr
if iter_type in self.serialize_type:
return [self.serialize_type[iter_type](i) for i in attr]
return [self.serilize_object(i) for i in attr]
def serialize_dict(self, attr, dict_type):
if dict_type in ['str','int']:
parse = eval(dict_type)
return {str(x):parse(attr[x]) for x in attr}
if dict_type in self.serialize_type:
return {str(x):self.serialize_type[dict_type](attr[x]) for x in attr}
return {str(x):self.serilize_object(attr[x]) for x in attr}
class Deserialized(object):
def __init__(self, response_obj):
self.response = self.unpack_response(response_obj)
self.deserialize_type = {
'str':self.deserialize_str,
'datetime':self.deserialize_datetime,
'duration':self.deserialize_int,
'time':self.deserialize_time,
'[]':self.deserialize_iter,
'{}':self.deserialize_dict
# etc
}
def __call__(self, raw):
if raw and self.response.body_map:
body = json.loads(raw)
for attr in self.response.body_map:
attr_type = self.response.body_map[attr]['type']
raw_value = body.get(self.response.body_map[attr]['name'])
value = self.deserialize_data(attr, raw_value, attr_type)
setattr(self.response, attr, value)
return response_obj
def deserialize_data(attr, data, data_type):
if data is None or data_type in ['str','int','bool']:
return data
if data_type in self.deserialize_type:
data_val = self.deserialize_type[data_type](data)
return data_val
iter_type = data_type[0] + data_type[-1]
if iter_type in self.deserialize_type:
return self.deserialize_type[iter_type](data, data_type[1,-1])
else:
deserialize_obj = Deserialized(eval(data_type))
return deserialize_obj(raw_data)
def unpack_response(response_type, raw_data):
response = response_type()
for attr in response.attributes_map:
attr_type = response.attributes_map[attr]['type']
raw_value = getattr(raw_data, response.attributes_map[attr]['name'])
value = self.deserialize_data(attr, raw_value, attr_type)
setattr(response, attr, value)
for attr in self.headers_map:
attr_type = response.headers_map[attr]['type']
raw_value = raw_data.headers.get(response.attributes_map[attr]['name'])
value = self.deserialize_data(attr, raw_value, attr_type)
setattr(response, attr, value)
return response

Просмотреть файл

@ -1,25 +0,0 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------

Просмотреть файл

@ -24,12 +24,6 @@
#
#--------------------------------------------------------------------------
class Authentication(object):
pass
class BasicAuthentication(Authentication):
pass
class TokenAuthentication(Authentication):
pass
from .service_client import ServiceClient
from .serialization import Serialized, Deserialized
from .configuration import Configuration

Просмотреть файл

@ -0,0 +1,86 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
"""
Define custom HTTP Adapter
"""
import requests
from .hooks import ClientPipelineHook
from .exceptions import InvalidHookError
class ClientHTTPAdapter(requests.adapters.HTTPAdapter):
def __init__(self):
self._client_headers = {}
self._client_hooks = {
'request':ClientPipelineHook(),
'response':ClientPipelineHook()}
super(ClientHTTPAdapter, self).__init__()
def event_hook(event):
def event_wrapper(func):
def execute_hook(self, *args, **kwargs):
return self._client_hooks[event](func, self, *args, **kwargs)
return execute_hook
return event_wrapper
def retry_handler(self, config):
pass
def proxy_handler(self, config):
pass
def redirect_handler(self, config):
pass
def add_hook(self, event, callback, precall=True, overwrite=False):
if not callable(callback):
raise InvalidHookError("Callback must be callable.")
if event not in self._client_hooks:
raise InvalidHookError("Event: '{0}' is not able to be hooked.".format(event))
if precall:
self._client_hooks[event].precalls.append(callback)
else:
self._client_hooks[event].postcalls.append(callback)
self._client_hooks[event].overwrite_call = overwrite
@event_hook("response")
def build_response(self, req, resp):
return super(ClientHTTPAdapter, self).build_response(req, resp)
@event_hook("request")
def send(self, request, stream = False, timeout = None, verify = True, cert = None, proxies = None):
return super(ClientHTTPAdapter, self).send(request, stream, timeout, verify, cert, proxies)

Просмотреть файл

@ -0,0 +1,75 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from base64 import b64encode
import time
import requests
import requests_oauthlib as oauth
from requests.auth import HTTPBasicAuth
class Authentication(object):
header = "Authorization"
def signed_session(self):
session = requests.Session()
return session
class BasicAuthentication(Authentication):
def __init__(self, username, passw):
self.scheme = 'Basic'
self.username = username
self.password = passw
def signed_session(self):
session = super(BasicAuthentication, self).signed_session()
session.auth = HTTPBasicAuth(self.username, self.password)
return session
class TokenAuthentication(Authentication):
def __init__(self, client_id, token):
self.scheme = 'Bearer'
self.id = client_id
self.token = token
def construct_auth(self):
return "{0} {1}".format(self.scheme, self.token)
def signed_session(self):
expiry = self.token.get('expires_at')
if expiry:
countdown = float(expiry) - time.time()
self.token['expires_in'] = countdown
session = oauth.OAuth2Session(self.id, token=self.token)
return session

Просмотреть файл

@ -0,0 +1,156 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
"""
Configuration of ServiceClient and session.
"""
import os
import tempfile
try:
import configparser
except ImportError:
import ConfigParser as configparser
from . import logger
class Configuration(object):
def __init__(self, base_url=None, filepath=None):
# Service
self.base_url = base_url
# Logging configuration
self._log_name = "ms-client-runtime"
self._log_dir = None
self._stream_logging = "%(asctime)-15s [%(levelname)s] %(module)s: %(message)s"
self._file_logging = "%(asctime)-15s [%(levelname)s] %(module)s: %(message)s"
self._level = 30
self._log = logger.setup_logger(self)
# Communication configuration - TODO: Populate
self.protocols = ['https://']
self.proxies = {}
self.timeout = None
self.allow_redirects = True
self.verify = True
self.cert = None
self._config = configparser.RawConfigParser()
self._config.optionxform = str
if filepath:
self.load(filepath)
@property
def log_level(self):
return self._level
@log_level.setter
def log_level(self, value):
val = logger.set_log_level(self._log, value)
self._level = val
@property
def stream_log(self):
return self._stream_logging
@stream_log.setter
def stream_log(self, value):
val = logger.set_stream_handler(self._log, value)
self._stream_logging = val
@property
def file_log(self):
return self._file_logging
@file_log.setter
def file_log(self, value):
val = logger.set_file_handler(self._log, self._log_dir, value)
self._file_logging = val
@property
def log_dir(self):
return self._log_dir
@log_dir.setter
def log_dir(self, value):
logger.set_file_handler(self._log, value, self._file_logging)
self._log_dir = value
@property
def log_name(self):
return self._log_name
@log_name.setter
def log_name(self, value):
self._log = setup_logger(self)
self._log_name = value
def save(self, filepath):
_config = configparser.RawConfigParser()
_config.add_section("Logging")
_config.add_section("HTTP")
_config.set("Logging", "log_name", self._log_name)
_config.set("Logging", "log_dir", self._log_dir)
_config.set("Logging", "stream_format", self._stream_logging)
_config.set("Logging", "file_format", self._file_logging)
_config.set("Logging", "level", self._level)
_config.set("HTTP", "protocols", self.protocols)
_config.set("HTTP", "timeout", self.timeout)
_config.set("HTTP", "allow_redirects", self.allow_redirects)
_config.set("HTTP", "verify", self.verify)
_config.set("HTTP", "cert", self.cert)
with open(filepath, 'w') as configfile:
self._config.write(configfile)
def load(self, filepath):
_config = configparser.RawConfigParser()
_config.read(filepath)
self._log_name = _config.get("Logging", "log_name")
self._log_dir = _config.get("Logging", "log_dir")
self._stream_logging = _config.get("Logging", "stream_format")
self._file_logging = _config.get("Logging", "file_format")
self._level = _config.getint("Logging", "level")
self.protocols = _config.get("HTTP", "protocols")
self.timeout = _config.get("HTTP", "timeout")
self.allow_redirects = _config.get("HTTP", "allow_redirects")
self.verify = _config.get("HTTP", "verify")
self.cert = _config.get("HTTP", "cert")
self._log = logger.setup_logger(self)

Просмотреть файл

@ -1,4 +1,4 @@
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
@ -22,4 +22,22 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class ClientException(Exception):
pass
class SerializationError(ClientException):
pass
class DeserializationError(ClientException):
pass
class InvalidOperationError(ClientException):
pass
class InvalidHookError(ClientException):
pass
class ResponseStatusError(ClientException):
pass

Просмотреть файл

@ -0,0 +1,58 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from requests.packages.urllib3 import Retry
class ClientRetryPolicy(object):
def __init__(self):
self.policy = Retry()
self.policy.total = 10
self.policy.connect = 3
self.policy.backoff_factor = 0.8
self.policy.BACKOFF_MAX = 90
@property
def max_retries(self):
return self.policy.total
@max_retries.setter
def max_retries(self, value):
self.policy.total = value
@property
def connect_retries(self):
return self.policy.connect
@max_retries.setter
def connect_retries(self, value):
self.policy.connect = value
class ClientProxyManager(object):
pass
class ClientRedirectHandler(object):
pass

Просмотреть файл

@ -0,0 +1,46 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
class ClientPipelineHook(object):
def __init__(self, overwrite=False):
self.precalls = []
self.postcalls = []
self.overwrite_call = overwrite
def __call__(self, func, *args, **kwargs):
result = None
for call in self.precalls:
result = call(result=result, *args, **kwargs)
if not self.overwrite_call:
result = func(*args, **kwargs)
for call in self.postcalls:
result = call(result=result, *args, **kwargs)
return result

Просмотреть файл

@ -0,0 +1,146 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
import os
import shutil
import logging
LOGGER = None
def invalid_directory(dirname):
try:
if not os.path.isdir(dirname):
os.mkdir(dirname)
with open(os.path.join(dirname, "ms_test"), 'w') as test_file:
test_file.write("All good to go!")
os.remove(os.path.join(dirname, "ms_test"))
return False
except (IOError, OSError, EnvironmentError) as exp:
return str(exp)
def set_stream_handler(logger, format_str):
current_handlers = [h for h in logger.handlers if isinstance(h, logging.StreamHandler)]
for handler in current_handlers:
logger.removeHandler(handler)
if format_str:
handler = logging.StreamHandler()
formatter = logging.Formatter(str(format_str))
handler.setFormatter(formatter)
logger.addHandler(handler)
return format_str
def set_file_handler(logger, file_dir, format_str):
current_handlers = [h for h in logger.handlers if isinstance(h, logging.FileHandler)]
for handler in current_handlers:
logger.removeHandler(handler)
if not format_str or not file_dir:
return format_str
check = invalid_directory(file_dir)
if check:
raise ValueError("Log directory '{0}' cannot be accessed: {1}".format(file_dir, check))
logfile = os.path.join(file_dir, logger.name + '.log')
if os.path.isfile(logfile) and os.path.getsize(logfile) > 10485760:
split_log = os.path.splitext(logfile)
timestamp = time.strftime("%Y-%m-%d-%H-%M-%S")
shutil.move(logfile, "{root}-{date}{ext}".format(
root=split_log[0],
date=timestamp,
ext=split_log[1]))
handler = logging.FileHandler(logfile)
formatter = logging.Formatter(str(format_str))
handler.setFormatter(formatter)
logger.addHandler(handler)
return format_str
def set_log_level(logger, level):
levels = {'debug': 10,
'info': 20,
'warning': 30,
'error': 40,
'critical': 50}
if isinstance(level, str) and level.lower() in levels:
level = levels[level.lower()]
try:
logger.setLevel(level)
except ValueError:
raise
return logger.level
def setup_logger(config):
global LOGGER
if LOGGER and LOGGER.name == config.log_name:
return LOGGER
logger = logging.getLogger(config.log_name)
if config.stream_log:
set_stream_handler(logger, config.stream_log)
if config.file_log:
set_file_handler(logger, config.log_dir, config.file_log)
set_log_level(logger, config.log_level)
LOGGER = logger
return logger
def log_request(adapter, request, *args, **kwargs):
#TODO: Proper log formatting
LOGGER.debug(str(request.headers))
LOGGER.debug(str(request.body))
LOGGER.debug(request.url)
return request
def log_response(adapter, request, response, *args, **kwargs):
#TODO: Proper log formatting
resp = kwargs.get('result')
LOGGER.debug(resp.status_code)
LOGGER.debug(resp.content)
return resp

Просмотреть файл

@ -0,0 +1,56 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
import requests
import json
"""
Wrappers for Resuests unprepared request objects
"""
class ClientRequest(requests.Request):
def __init__(self, config):
super(ClientRequest, self).__init__()
self.timeout = config.timeout
self.allow_redirects = config.allow_redirects
self.verify = config.verify
self.cert = config.cert
def add_header(self, header, value):
self.headers[header] = value
def add_headers(self, headers):
for key, value in headers.items():
self.add_header(key, value)
def add_content(self, data):
self.data = json.dumps(data())
self.headers['Content-Length'] = len(self.data)

Просмотреть файл

@ -24,17 +24,21 @@
#
#--------------------------------------------------------------------------
from .exceptions import ResponseStatusError
class HTTPResponse(object):
accept_status = [200]
def __init__(self):
self.headers_map = {}
self.attributes_map = {
'status_code': {'name':'status_code', 'type':'str'}
'status_code': {'key':'status_code', 'type':'str'}
}
self.body_map = {}
self._status_code
self._status_code = None
@property
def status_code(self):
@ -42,4 +46,6 @@ class HTTPResponse(object):
@status_code.setter
def status_code(self, value):
if int(value) not in self.accept_status:
raise ResponseStatusError()
self._status_code = value

Просмотреть файл

@ -0,0 +1,292 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from .response import HTTPResponse
import json
import isodate
import datetime
from .exceptions import SerializationError, DeserializationError
class Serialized(object):
basic_types = ['str', 'int', 'bool', 'float']
def __init__(self, request_obj):
self.request = request_obj
self.serialize_type = {
'iso-date':Serialized.serialize_date,
'duration':Serialized.serialize_duration,
'[]':self.serialize_iter,
'{}':self.serialize_dict
# etc
}
def __getattr__(self, attr):
try:
orig_attr = getattr(self.request, attr)
attr_type = self.request._attribute_map[attr]['type']
return self._serialize_data(orig_attr, attr_type, attr in self.request._required)
except (AttributeError, KeyError, TypeError) as err:
raise SerializationError(
"Attribute {0} cannot be serialized: {1}".format(attr, err))
def __call__(self):
serialized = {}
attr_name = None
try:
for attr, map in self.request._attribute_map.items():
attr_name = attr
try:
serialized[map['key']] = getattr(self, attr)
except ValueError:
continue
except (AttributeError, KeyError, TypeError) as err:
raise SerializationError(
"Attribute {0} cannot be serialized: {1}".format(attr_name, err))
return serialized
def _serialize_data(self, data, data_type, required):
if data is None and required:
class_name = self.request.__class__.__name__
raise AttributeError(
"Object '{}' missing required attribute".format(class_name))
if not data:
raise ValueError("No value for given attribute")
if data_type is None:
return data
try:
if data_type in self.basic_types:
return eval(data_type)(data)
if data_type in self.serialize_type:
return self.serialize_type[data_type](data)
iter_type = data_type[0] + data_type[-1]
if iter_type in self.serialize_type:
return self.serialize_type[iter_type](data, data_type[1:-1], required)
except (ValueError, TypeError) as err:
raise SerializationError("Unable to serialize value: '{0}' as type: {1}".format(data, data_type))
return self.serialize_object(data)
def serialize_object(self, cmplx_obj):
serialized = Serialized(cmplx_obj)
return serialized()
def serialize_iter(self, data, iter_type, required):
return [self._serialize_data(i, iter_type, required) for i in data]
def serialize_dict(self, attr, dict_type, required):
return {str(x):self._serialize_data(attr[x], dict_type, required) for x in attr}
@staticmethod
def serialize_duration(attr):
return str(attr) #TODO
@staticmethod
def serialize_opc_date(attr):
date_str = date_obj.strftime('%a, %d %b %Y %H:%M:%S GMT')
return date_str
@staticmethod
def serialize_date(attr):
if isinstance(attr, str):
attr = isodate.parse_datetime(attr)
try:
utc = attr.utctimetuple()
microseconds = str(float(attr.microsecond)*1e-6)[1:].ljust(4, '0')
date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format(
utc.tm_year,utc.tm_mon,utc.tm_mday,utc.tm_hour,utc.tm_min,utc.tm_sec)
return date + microseconds + 'Z'
except (ValueError, OverflowError) as err:
raise SerializationError("Unable to serialize datetime object: {0}".format(err))
class DeserializedGenerator(object):
def __init__(self, deserialize, resp_lst, resp_type):
self._command = deserialize
self._type = resp_type
self._list = resp_lst
def __iter__(self):
for resp in self._list:
yield self._command(resp, self._type)
class Deserialized(object):
basic_types = ['str', 'int', 'bool', 'float']
def __init__(self, response_obj, response_data=None, manager=None, key=None):
self.deserialize_type = {
'iso-date':Deserialized.deserialize_date,
'duration':Deserialized.deserialize_duration,
'time':Deserialized.deserialize_time,
'[]':self.deserialize_iter,
'{}':self.deserialize_dict
# etc
}
self.key = key
self.client = manager
self.response = response_obj(manager=self.client, response=response_data)
self.dependencies = {}
if response_data is not None:
try:
self.unpack_response(response_data)
except (AttributeError, TypeError, KeyError) as err:
raise DeserializationError("Unable to deserialize to type: '{0}' because: '{1}'.".format(response_obj, err))
def __call__(self, raw=None, classes={}):
self.dependencies = dict(classes)
if raw:
raw = json.loads(raw)
if self.key:
print(self.key, raw)
raw = raw.get(self.key)
if isinstance(raw, list):
data_type = self.response.__class__.__name__
return DeserializedGenerator(self._deserialize_data, raw, data_type)
map_dict = getattr(self.response, '_attribute_map')
for attr in map_dict:
attr_type = map_dict[attr]['type']
key = map_dict[attr]['key']
raw_value = raw.get(key) if key else raw
value = self._deserialize_data(raw_value, attr_type)
setattr(self.response, attr, value)
return self.response
def _deserialize_data(self, data, data_type):
if data is None:
return data
try:
if not data_type:
return data
if data_type in self.basic_types:
return eval(data_type)(data)
if data_type in self.deserialize_type:
data_val = self.deserialize_type[data_type](data)
return data_val
iter_type = data_type[0] + data_type[-1]
if iter_type in self.deserialize_type:
return self.deserialize_type[iter_type](data, data_type[1:-1])
except (ValueError, TypeError) as err:
raise DeserializationError("Unable to deserialize response data: {0}".format(err))
deserialize_obj = Deserialized(self.dependencies[data_type], manager=self.client)
return deserialize_obj(json.dumps(data), self.dependencies)
def unpack_response(self, raw_data):
if hasattr(self.response, '_header_map'):
for attr, val in self.response._header_map.items():
attr_type = val['type']
attr_name = val['key']
raw_value = raw_data.headers.get(attr_name)
value = self._deserialize_data(raw_value, attr_type)
setattr(self.response, attr, value)
if hasattr(self.response, '_response_map'):
for attr, val in self.response._response_map.items():
attr_type = val['type']
attr_name = val['key']
raw_value = getattr(raw_data, attr_name)
value = self._deserialize_data(raw_value, attr_type)
setattr(self.response, attr, value)
def deserialize_iter(self, attr, iter_type):
return DeserializedGenerator(self._deserialize_data, attr, iter_type)
def deserialize_dict(self, attr, dict_type):
if isinstance(attr, list):
return {str(x['key']):self._deserialize_data(x['value'], dict_type) for x in attr}
return {str(x):self._deserialize_data(attr[x], dict_type) for x in attr}
@staticmethod
def deserialize_duration(attr):
return attr #TODO
@staticmethod
def deserialize_time(attr):
return attr #TODO
@staticmethod
def deserialize_date(attr):
try:
date_obj = isodate.parse_datetime(attr)
t = date_obj.utctimetuple()
return date_obj
except(ValueError, OverflowError, AttributeError) as err:
raise DeserializationError("Cannot deserialize datetime object: {}".format(err))

Просмотреть файл

@ -0,0 +1,119 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
try:
from urlparse import urljoin
from urllib import quote
except ImportError:
from urllib.parse import urljoin, quote
from .request import ClientRequest
from .adapter import ClientHTTPAdapter
from .logger import log_request, log_response
class ServiceClient(object):
def __init__(self, creds, config):
"""
Create service client.
:Args:
- config (`.Configuration`): Service configuration.
- creds (`.Authentication`): Authenticated credentials.
"""
self.config = config
self.creds = creds
self._adapter = ClientHTTPAdapter()
self._adapter.retry_handler(config)
self._adapter.add_hook("request", log_request)
self._adapter.add_hook("response", log_response, precall=False)
def _format_url(self, url):
url = quote(url)
url = urljoin(self.config.base_url, url)
return url
def _request(self, url, params):
request = ClientRequest(self.config)
if url:
request.url = self._format_url(url)
if params:
request.params = params
return request
def send(self, request, **kwargs):
session = self.creds.signed_session()
session.proxies = self.config.proxies
for protocol in self.config.protocols:
session.mount(protocol, self._adapter)
prepped = session.prepare_request(request)
return session.send(prepped)
def add_hook(self, hook):
self.adapter.add_hook(event, hook)
def add_header(self, header, value):
self._adapter.client_headers[header] = value
def get(self, url=None, params={}):
request = self._request(url, params)
request.method = 'GET'
return request
def put(self, url=None, params={}):
request = self._request(url, params)
request.method = 'PUT'
return request
def post(self, url=None, params={}):
request = self._request(url, params)
request.method = 'POST'
return request
def patch(self, url=None, params={}):
request = self._request(url, params)
request.method = 'PATCH'
return request
def delete(self, url=None, params={}):
request = self._request(url, params)
request.method = 'DELETE'
return request
def merge(self, url=None, params={}):
request = self._request(url, params)
request.method = 'MERGE'
return request

Просмотреть файл

@ -0,0 +1,68 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
import sys
import os
if sys.version_info[:2] < (2, 7, ):
try:
import unittest2
from unittest2 import TestLoader, TextTestRunner
except ImportError:
raise ImportError("The Python Client Runtime test suite requires "
"the unittest2 package to run on Python 2.6 and "
"below.\nPlease install this package to continue.")
else:
import unittest
from unittest import TestLoader, TextTestRunner
if sys.version_info[:2] >= (3, 3, ):
from unittest import mock
else:
try:
import mock
except ImportError:
raise ImportError("The Python Client runtime test suite requires "
"the mock package to run on Python 3.2 and below.\n"
"Please install this package to continue.")
if __name__ == '__main__':
runner = TextTestRunner(verbosity=2)
test_dir = os.path.dirname(__file__)
top_dir = os.path.dirname(os.path.dirname(test_dir))
sys.path.append(top_dir)
test_loader = TestLoader()
suite = test_loader.discover(test_dir,
pattern="unittest_*.py",
top_level_dir=top_dir)
runner.run(suite)

Просмотреть файл

@ -0,0 +1,589 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
import sys
import json
try:
import unittest2 as unittest
except ImportError:
import unittest
try:
from unittest import mock
except ImportError:
import mock
from msrest import Serialized, Deserialized
from msrest.exceptions import SerializationError, DeserializationError
from requests import Response
class TestRuntimeSerialized(unittest.TestCase):
class TestObj(object):
def __init__(self):
self._required = []
self._attribute_map = {
'attr_a': {'key':'id', 'type':'str'},
'attr_b': {'key':'AttrB', 'type':'int'},
'attr_c': {'key':'Key_C', 'type': 'bool'},
'attr_d': {'key':'AttrD', 'type':'[int]'},
'attr_e': {'key':'AttrE', 'type': '{float}'}
#TODO: Add more here as more types are defined in serialized
}
self.attr_a = None
self.attr_b = None
self.attr_c = None
self.attr_d = None
self.attr_e = None
def setUp(self):
return super(TestRuntimeSerialized, self).setUp()
def test_obj_without_attr_map(self):
"""
Test serializing an object with no attribute_map.
"""
test_obj = type("BadTestObj", (), {})
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
def test_obj_with_malformed_map(self):
"""
Test serializing an object with a malformed attribute_map.
"""
test_obj = type("BadTestObj", (), {"attribute_map":None})
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
test_obj.attribute_map = {"attr":"val"}
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
test_obj.attribute_map = {"attr":{"val":1}}
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
def test_obj_with_mismatched_map(self):
"""
Test serializing an object with mismatching attributes and map.
"""
test_obj = type("BadTestObj", (), {"attribute_map":None})
test_obj.attribute_map = {"abc":{"key":"ABC", "type":"str"}}
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
def test_attr_none(self):
"""
Test serializing an object with None attributes.
"""
test_obj = self.TestObj()
serialized = Serialized(test_obj)
message = serialized()
self.assertIsInstance(message, dict)
self.assertFalse('id' in message)
def test_attr_int(self):
"""
Test serializing an object with Int attributes.
"""
test_obj = self.TestObj()
test_obj._required = ['attr_b']
test_obj.attr_b = None
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
test_obj.attr_b = 25
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_b, 25)
message = serialized()
self.assertEqual(message['AttrB'], 25)
test_obj.attr_b = "34534"
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_b, 34534)
message = serialized()
self.assertEqual(message['AttrB'], 34534)
test_obj.attr_b = "NotANumber"
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
def test_attr_str(self):
"""
Test serializing an object with Str attributes.
"""
test_obj = self.TestObj()
test_obj._required = ['attr_a']
test_obj.attr_a = None
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
self.assertIsNone(serialized.attr_a)
test_obj._required = []
serialized = Serialized(test_obj)
test_obj.attr_a = "TestString"
serialized = Serialized(test_obj)
message = serialized()
self.assertEqual(message['id'], "TestString")
test_obj.attr_a = 1234
serialized = Serialized(test_obj)
message = serialized()
self.assertEqual(message['id'], "1234")
test_obj.attr_a = list()
serialized = Serialized(test_obj)
message = serialized()
self.assertFalse('id' in message)
test_obj.attr_a = [1]
serialized = Serialized(test_obj)
message = serialized()
self.assertEqual(message['id'], "[1]")
def test_attr_bool(self):
"""
Test serializing an object with bool attributes.
"""
test_obj = self.TestObj()
test_obj.attr_c = True
serialized = Serialized(test_obj)
self.assertIs(serialized.attr_c, True)
message = serialized()
self.assertEqual(message['Key_C'], True)
test_obj.attr_c = ""
serialized = Serialized(test_obj)
message = serialized()
self.assertFalse('Key_C' in message)
test_obj.attr_c = None
serialized = Serialized(test_obj)
message = serialized()
self.assertFalse('Key_C' in message)
test_obj.attr_c = "NotEmpty"
serialized = Serialized(test_obj)
self.assertIs(serialized.attr_c, True)
message = serialized()
self.assertEqual(message['Key_C'], True)
def test_attr_list_simple(self):
"""
Test serializing an object with simple-typed list attributes
"""
test_obj = self.TestObj()
test_obj.attr_d = []
serialized = Serialized(test_obj)
message = serialized()
self.assertFalse('AttrD' in message)
test_obj.attr_d = [1,2,3]
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_d, [1,2,3])
message = serialized()
self.assertEqual(message['AttrD'], [1,2,3])
test_obj.attr_d = ["1","2","3"]
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_d, [1,2,3])
message = serialized()
self.assertEqual(message['AttrD'], [1,2,3])
test_obj.attr_d = ["test","test2","test3"]
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
test_obj.attr_d = "NotAList"
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized()
def test_attr_list_complex(self):
"""
Test serializing an object with a list of complex objects as an attribute.
"""
list_obj = type("ListObj", (), {"_attribute_map":None,
"_required":[],
"abc":None})
list_obj._attribute_map = {"abc":{"key":"ABC", "type":"int"}}
list_obj.abc = "123"
test_obj = type("CmplxTestObj", (), {"_attribute_map":None,
"_required":[],
"test_list":None})
test_obj._attribute_map = {"test_list":{"key":"_list", "type":"[ListObj]"}}
test_obj.test_list = [list_obj]
serialized = Serialized(test_obj)
self.assertEqual(serialized.test_list[0].get('ABC'), 123)
message = serialized()
self.assertEqual(message, {'_list':[{'ABC':123}]})
list_obj = type("BadListObj", (), {"map":None})
test_obj.attribute_map = {"test_list":{"key":"_list", "type":"[BadListObj]"}}
test_obj.test_list = [list_obj]
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized.test_list
def test_attr_dict_simple(self):
"""
Test serializing an object with a simple dictionary attribute.
"""
test_obj = self.TestObj()
test_obj.attr_e = {"value": 3.14}
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_e["value"], 3.14)
message = serialized()
self.assertEqual(message['AttrE']['value'], 3.14)
test_obj.attr_e = {1: "3.14"}
serialized = Serialized(test_obj)
self.assertEqual(serialized.attr_e["1"], 3.14)
message = serialized()
self.assertEqual(message['AttrE']['1'], 3.14)
test_obj.attr_e = "NotADict"
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized.attr_e
test_obj.attr_e = {"value": "NotAFloat"}
serialized = Serialized(test_obj)
with self.assertRaises(SerializationError):
serialized.attr_e
class TestRuntimeDeserialized(unittest.TestCase):
class TestObj(object):
def __init__(self, **kwargs):
self.body_map = {
'attr_a': {'key':'id', 'type':'str'},
'attr_b': {'key':'AttrB', 'type':'int'},
'attr_c': {'key':'Key_C', 'type': 'bool'},
'attr_d': {'key':'AttrD', 'type':'[int]'},
'attr_e': {'key':'AttrE', 'type': '{float}'}
#TODO: Add more here as more types are defined in serialized
}
self.headers_map = {
'client_request_id': {'key': 'client-request-id', 'type':'str'},
'e_tag': {'key': 'etag', 'type':'str'},
}
self.attributes_map = {
'status_code': {'key':'status_code', 'type':'str'}
}
self.status_code = None
def test_obj_with_no_attr(self):
"""
Test deserializing an object with no attributes.
"""
class EmptyResponse(object):
def __init__(*args, **kwargs):
pass
response_data = mock.create_autospec(Response)
with self.assertRaises(DeserializationError):
deserializer = Deserialized(EmptyResponse, response_data)
class BetterEmptyResponse(object):
attributes_map = {}
headers_map = {}
body_map = {}
def __init__(*args, **kwargs):
pass
deserializer = Deserialized(BetterEmptyResponse, response_data)
derserialized = deserializer(None)
self.assertIsInstance(derserialized, BetterEmptyResponse)
def test_obj_with_malformed_map(self):
"""
Test deserializing an object with a malformed attributes_map.
"""
response_data = mock.create_autospec(Response)
class BadResponse(object):
attributes_map = None
def __init__(*args, **kwargs):
pass
with self.assertRaises(DeserializationError):
deserializer = Deserialized(BadResponse, response_data)
class BadResponse(object):
attributes_map = {"attr":"val"}
def __init__(*args, **kwargs):
pass
with self.assertRaises(DeserializationError):
deserializer = Deserialized(BadResponse, response_data)
class BadResponse(object):
attributes_map = {"attr":{"val":1}}
def __init__(*args, **kwargs):
pass
with self.assertRaises(DeserializationError):
deserializer = Deserialized(BadResponse, response_data)
def test_obj_with_mismatched_map(self):
"""
Test deserializing an object with mismatching attributes and map.
"""
response_data = mock.create_autospec(Response)
class BadResponse(object):
attributes_map = {"abc":{"key":"ABC", "type":"str"}}
def __init__(*args, **kwargs):
pass
with self.assertRaises(DeserializationError):
deserializer = Deserialized(BadResponse, response_data)
def test_attr_none(self):
"""
Test serializing an object with None attributes.
"""
response_data = mock.create_autospec(Response)
with self.assertRaises(DeserializationError):
deserializer = Deserialized(self.TestObj, response_data)
self.assertIsNone(deserializer.attr_a)
response_data.status_code = None
response_data.headers = {'client-request-id':None, 'etag':None}
deserializer = Deserialized(self.TestObj, response_data)
response = deserializer(None)
self.assertIsNone(response.status_code)
self.assertIsNone(response.client_request_id)
self.assertIsNone(response.e_tag)
self.assertFalse(hasattr(response, 'attr_a'))
self.assertIsInstance(response, self.TestObj)
def test_attr_int(self):
"""
Test deserializing an object with Int attributes.
"""
response_data = mock.create_autospec(Response)
response_data.status_code = 200
response_data.headers = {'client-request-id':"123", 'etag':456.3}
deserializer = Deserialized(self.TestObj, response_data)
response = deserializer(None)
self.assertEqual(response.status_code, "200")
self.assertEqual(response.client_request_id, "123")
self.assertEqual(response.e_tag, "456.3")
response = deserializer(json.dumps({'AttrB':'1234'}))
self.assertTrue(hasattr(response, 'attr_b'))
self.assertEqual(response.attr_b, 1234)
with self.assertRaises(DeserializationError):
response = deserializer(json.dumps({'AttrB':'NotANumber'}))
def test_attr_str(self):
"""
Test deserializing an object with Str attributes.
"""
response_data = mock.create_autospec(Response)
response_data.status_code = 200
response_data.headers = {'client-request-id': 'a', 'etag': 'b'}
deserializer = Deserialized(self.TestObj, response_data)
response = deserializer(json.dumps({'id':'InterestingValue'}))
self.assertTrue(hasattr(response, 'attr_a'))
self.assertEqual(response.attr_a, 'InterestingValue')
response = deserializer(json.dumps({'id':1234}))
self.assertEqual(response.attr_a, '1234')
response = deserializer(json.dumps({'id':list()}))
self.assertEqual(response.attr_a, '[]')
response = deserializer(json.dumps({'id':None}))
self.assertEqual(response.attr_a, None)
def test_attr_bool(self):
"""
Test deserializing an object with bool attributes.
"""
response_data = mock.create_autospec(Response)
response_data.status_code = 200
response_data.headers = {'client-request-id': 'a', 'etag': 'b'}
deserializer = Deserialized(self.TestObj, response_data)
response = deserializer(json.dumps({'Key_C':True}))
self.assertTrue(hasattr(response, 'attr_c'))
self.assertEqual(response.attr_c, True)
response = deserializer(json.dumps({'Key_C':[]}))
self.assertEqual(response.attr_c, False)
response = deserializer(json.dumps({'Key_C':0}))
self.assertEqual(response.attr_c, False)
response = deserializer(json.dumps({'Key_C':"Value"}))
self.assertEqual(response.attr_c, True)
def test_attr_list_simple(self):
"""
Test deserializing an object with simple-typed list attributes
"""
response_data = mock.create_autospec(Response)
response_data.status_code = 200
response_data.headers = {'client-request-id': 'a', 'etag': 'b'}
deserializer = Deserialized(self.TestObj, response_data)
data = {'AttrD': []}
response = deserializer(json.dumps(data))
deserialized_list = [d for d in response.attr_d]
self.assertEqual(deserialized_list, [])
data['AttrD'] = [1,2,3]
response = deserializer(json.dumps(data))
deserialized_list = [d for d in response.attr_d]
self.assertEqual(deserialized_list, [1,2,3])
data['AttrD'] = ["1","2","3"]
response = deserializer(json.dumps(data))
deserialized_list = [d for d in response.attr_d]
self.assertEqual(deserialized_list, [1,2,3])
data['AttrD'] = ["test","test2","test3"]
with self.assertRaises(DeserializationError):
response = deserializer(json.dumps(data))
deserialized_list = [d for d in response.attr_d]
data['AttrD'] = "NotAList"
with self.assertRaises(DeserializationError):
response = deserializer(json.dumps(data))
deserialized_list = [d for d in response.attr_d]
def test_attr_list_complex(self):
"""
Test deserializing an object with a list of complex objects as an attribute.
"""
class ListObj(object):
_attribute_map = {"abc":{"key":"ABC", "type":"int"}}
def __init__(*args, **kwargs):
pass
class CmplxTestObj(object):
def __init__(self, **kwargs):
self.attributes_map = {}
self.headers_map = {}
self.body_map = {'attr_a': {'key':'id', 'type':'[ListObj]'}}
response_data = mock.create_autospec(Response)
response_data.status_code = 200
response_data.headers = {'client-request-id': 'a', 'etag': 'b'}
deserializer = Deserialized(CmplxTestObj)
data = {"id":[{"ABC": "123"}]}
response = deserializer(json.dumps(data), {'ListObj':ListObj})
deserialized_list = [a for a in response.attr_a]
self.assertIsInstance(deserialized_list[0], ListObj)
self.assertEqual(deserialized_list[0].abc, 123)

Просмотреть файл

@ -23,17 +23,8 @@
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
"""
Define custom HTTP Adapter
"""
import requests
class ClientHTTPAdapter(requests.adapters.HTTPAdapter):
def __init__(self, retry, headers, hooks):
pass
def format_datetime_header(date_obj):
date_str = date_obj.strftime('%a, %d %b %Y %H:%M:%S GMT')
return date_str

Просмотреть файл

@ -24,9 +24,6 @@
#
#--------------------------------------------------------------------------
"""
Configuration of ServiceClient and session.
"""
class Configuration(object):
pass
from .azure_configuration import AzureConfiguration
from .azure_service_client import AzureServiceClient

Просмотреть файл

@ -0,0 +1,367 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from ..msrest.authentication import Authentication, TokenAuthentication
from .azure_configuration import AzureConfiguration
import requests_oauthlib as oauth
from oauthlib.oauth2 import BackendApplicationClient, LegacyApplicationClient
from requests.auth import AuthBase
import time
import keyring
import ast
import base64
import hmac
import hashlib
try:
from urlparse import urlparse, parse_qs
except ImportError:
from urllib.parse import urlparse, parse_qs
def _http(base_uri, *extra):
parts = [str(e).strip('/') for e in extra]
str_parts = '/'.join(parts)
str_base = str(base_uri)
if str_base.startswith("http://"):
return "{0}/{1}".format(str_base, str_parts)
elif str_base.startswith("https://"):
return "{0}/{1}".format(str_base.replace("https:","http:", 1), str_parts)
else:
return "http://{0}/{1}".format(str_base, str_parts)
def _https(base_uri, *extra):
parts = [str(e).strip('/') for e in extra]
str_parts = '/'.join(parts)
str_base = str(base_uri)
if str_base.startswith("https://"):
return "{0}/{1}".format(str_base, str_parts)
elif str_base.startswith("http://"):
return "{0}/{1}".format(str_base.replace("http:","https:", 1), str_parts)
else:
return "https://{0}/{1}".format(str_base, str_parts)
class AADMixin(object):
def _configure(self, config):
if not config:
config = AzureConfiguration()
self.auth_uri = _https(config.auth_endpoint, config.tenant, config.auth_uri)
self.token_uri = _https(config.auth_endpoint, config.tenant, config.token_uri)
self.verify = config.verify
self.cred_store = config.keyring
self.state = state = oauth.oauth2_session.generate_token()
def _check_state(response):
state_key = '&state='
state_idx = response.find(state_key)
if state_idx < 0:
return False
strt_idx = state_idx + len(state_key)
end_idx = response.find('&', strt_idx)
state_val = response[strt_idx:end_idx]
return state_val == self.state
def _store_token(self, token):
self.token = token
keyring.set_password(self.cred_store, self.id, str(token))
def _retrieve_stored_token(self):
token = keyring.get_password(self.cred_store, self.id)
if token is None:
raise Exception() #TODO
else:
return ast.literal_eval(str(token))
def _clear_token(self):
try:
keyring.delete_password(self.cred_store, self.id)
except:
raise
class UserPassCredentials(TokenAuthentication, AADMixin):
def __init__(self, client_id, username, password, secret=None, config=None):
super(InteractiveAuth, self).__init__(client_id, None)
self._configure(config)
self.username = username
self.password = password
self.secret = secret
self.client = LegacyApplicationClient(self.id)
def get_token(self):
session = oauth.OAuth2Session(self.id, client=self.client)
optional = {}
if self.secret:
optional['client_secret'] = self.secret
try:
token = session.fetch_token(self.token_uri, client_id=self.id,
username=self.username, password=self.password,
**optional)
except:
raise
self.token = token
return token
class ServicePrincipalCredentials(TokenAuthentication, AADMixin):
def __init__(self, client_id, secret, resource, tenant=None, config=None):
if not config:
config = AzureConfiguration()
if tenant:
config.tenant = tenant
super(InteractiveAuth, self).__init__(client_id, None)
self._configure(config)
self.secret = secret
self.resource = resource
self.client = BackendApplicationClient(self.id)
def get_token(self):
session = oauth.OAuth2Session(self.id, client=self.client)
try:
token = session.fetch_token(self.token_uri, client_id=self.id,
resource=self.resource,
client_secret=self.secret,
response_type="client_credentials",
verify=self.verify)
except oauth2.rfc6749.errors.InvalidGrantError as excp:
raise
except oauth2.rfc6749.errors.OAuth2Error as excp:
raise
self.token = token
return token
class InteractiveCredentials(TokenAuthentication, AADMixin):
def __init__(self, client_id, resource, redirect, config=None):
super(InteractiveAuth, self).__init__(client_id, None)
self._configure(config)
self.resource = resource
self.redirect = redirect
def _setup_session(self):
return oauth.OAuth2Session(self.id, redirect_uri=self.redirect,
state=self.state)
def retrieve_session(self):
try:
self.token = self._retrieve_stored_token()
self.signed_session()
return token
except:
raise
def get_auth_url(self, msa=False, **additional_args):
if msa:
additional_args['domain_hint'] = 'live.com'
session = self._setup_session()
auth_url, state = session.authorization_url(self.auth_uri, resource=self.resource, **additional_args)
return auth_url, state
def get_token(self, response_url):
if not self._check_state(response_url):
raise Exception() #TODO
session = self._setup_session()
if response_url.startswith(_http(self.redirect)):
response_url = _https(response_url)
elif not response_url.startswith(_https(self.redirect)):
response_url = _https(self.redirect) + response_url
try:
token = session.fetch_token(self.token_uri,
authorization_response=response_url,
verify=self.verify)
except oauth2.rfc6749.errors.InvalidGrantError as excp:
raise
except oauth2.rfc6749.errors.OAuth2Error as excp:
raise
except oauth2.rfc6749.errors.MismatchingStateError as excep:
raise
self.token = token
return token
def signed_session(self):
countdown = float(self.token['expires_at']) - time.time()
self.token['expires_in'] = countdown
try:
new_session = oauth.OAuth2Session(
self.id,
token=self.token,
auto_refresh_url=self.token_uri,
auto_refresh_kwargs={'client_id':self.id,
'resource':self.resource},
token_updater=self._store_auth)
return new_session
except oauth2.rfc6749.errors.TokenExpiredError as err:
#TODO: Error handling
raise
class SharedKeyAuth(AuthBase):
def __init__(self, header, account_name, key):
self._header = header
self._account_name = account_name
self._key = key
def __call__(self, request):
url = urlparse(request.url);
uri_path = url.path;
# method to sign
string_to_sign = request.method + '\n'
# get headers to sign
headers_to_sign = [
'content-encoding', 'content-language', 'content-length',
'content-md5', 'content-type', 'date', 'if-modified-since',
'if-match', 'if-none-match', 'if-unmodified-since', 'range']
request_header_dict = dict((name.lower(), value)
for name, value in request.headers.iteritems() if value)
string_to_sign += '\n'.join(request_header_dict.get(x, '')
for x in headers_to_sign) + '\n'
# get ocp- header to sign
ocp_headers = []
for name, value in request.headers.iteritems():
if 'ocp-' in name:
ocp_headers.append((name.lower(), value))
ocp_headers.sort()
for name, value in ocp_headers:
if value:
string_to_sign += ''.join([name, ':', value, '\n'])
# get account_name and uri path to sign
string_to_sign += '/' + self._account_name + uri_path
# get query string to sign if it is not table service
query_to_sign = parse_qs(url.query)
for name in sorted(query_to_sign.iterkeys()):
if query_to_sign[name][0]:
string_to_sign += '\n' + name + ':' + query_to_sign[name][0]
# sign the request
auth_string = 'SharedKey ' + self._account_name + ':' + \
self._sign_string(string_to_sign)
request.headers[self._header] = auth_string
return request
def _sign_string(self, string_to_sign):
if isinstance(self._key, unicode):
self._key = self._key.encode('utf-8')
key = base64.b64decode(self._key)
if isinstance(string_to_sign, unicode):
string_to_sign = string_to_sign.encode('utf-8')
signed_hmac_sha256 = hmac.HMAC(key, string_to_sign, hashlib.sha256)
digest = signed_hmac_sha256.digest()
return base64.b64encode(digest)
class SharedKeyCredentials(Authentication):
def __init__(self, account_name, key):
super(SharedKeyCredentials, self).__init__()
self.auth = SharedKeyAuth(self.header, account_name, key)
def signed_session(self):
session = super(SharedKeyCredentials, self).signed_session()
session.auth = self.auth
return session

Просмотреть файл

@ -24,21 +24,19 @@
#
#--------------------------------------------------------------------------
class ServiceClient(object):
def __init__(self, config, creds):
"""
Create service client.
from ..msrest import Configuration
:Args:
- config (`.Configuration`): Service configuration.
- creds (`.Authentication`): Authenticated credentials.
class AzureConfiguration(Configuration):
"""
pass
def __init__(self, base_url=None, filepath=None):
def add_hook(self, event, hook):
pass
super(AzureConfiguration, self).__init__(base_url, filepath)
def add_header(self, header, value):
pass
# Authentication
self.auth_endpoint = "login.windows.net/"
self.token_uri = "/oauth2/token"
self.auth_uri = "/oauth2/authorize"
self.tenant = "common"
self.resource = 'https://management.core.windows.net/'
self.keyring = "AzureAAD"

Просмотреть файл

@ -0,0 +1,71 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from ..msrest.serialization import Deserialized
class CloudError(Exception):
_response_map = {
'status_code': {'key':'status_code', 'type':'str'}
}
_attribute_map = {
'error': {'key':'code', 'type':'str'},
'message': {'key':'message', 'type':'{str}'},
'data': {'key':'values', 'type':'{str}'}
}
def __init__(self, *args, **kwargs):
self.error = None
self.status_code = None
self._message = None
self.request_id = None
self.error_time = None
self.data = None
super(CloudError, self).__init__(*args)
def __str__(self):
return self._message
@property
def message(self):
return self._message
@message.setter
def message(self,value):
try:
if value.get('value'):
msg_data = value['value'].split('\n')
self._message = msg_data[0]
self.request_id = msg_data[1].split(':')[1]
self.error_time = Deserialized.deserialize_date(msg_data[2].split(':')[1])
except (AttributeError, IndexError):
self._message = value

Просмотреть файл

@ -0,0 +1,115 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from threading import Thread, Event
import time
import pickle
class Paged(object):
def __init__(self, items, url, command):
self.items = items
self.url = url
self.command = command
def __iter__(self):
for i in self.items:
yield i
while self.url is not None:
self.items, self.url = self.command(self.url)
for i in self.items:
yield i
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
class Polled(object):
def __init__(self, response, update_cmd):
self._response = response
self._url = self._extract_url()
self._callbacks = []
self._done = Event()
self._thread = Thread(target=self._poll, args=(update_cmd,))
self._thread.start()
def _extract_url(self):
if self._response.asyncoperation:
return self._response.asyncoperation
elif self._response.location:
return self._response.location
def _poll(self, update):
while True:
time.sleep(POLLING_DELAY)
self._response = update(self._url)
if self._response.status_code in []:
self._done.set()
break
callbacks = list(self._callbacks)
for call in callbacks:
call(self._response)
if len(callbacks) != len(self._callbacks):
more_calls = [c for c in self._callbacks if c not in callbacks]
for call in more_calls:
call(self._response)
def result(timeout=None):
self.wait(timeout)
return self._response
def wait(timeout=None):
self._thread.join(timeout=timeout)
def done(self):
return not self._thread.isAlive()
def add_done_callback(func):
if self._done.is_set():
raise Exception("Process is complete.")
self._callbacks.append(func)
def remove_done_callback(func):
if self._done.is_set():
raise Exception("Process is complete")
self._callbacks = [c for c in self._callbacks if c != func]

Просмотреть файл

@ -23,5 +23,3 @@
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from .serialization import Serializer

Просмотреть файл

@ -24,31 +24,15 @@
#
#--------------------------------------------------------------------------
import requests
class AzureResponse(HTTPResponse):
"""
Wrappers for Resuests unprepared request objects
"""
def __init__(self):
def get():
pass
def put():
pass
def post():
pass
def head():
pass
def delete():
pass
def patch():
pass
def merge():
pass
super(AzureResponse, self).__init__()
self.headers_map.update(
{'asyncoperation':{'key':'azure-asyncoperation','type':'str'},
'location':{'key':'location','type':'str'}})
self.asyncoperation = None
self.location = None

Просмотреть файл

@ -0,0 +1,59 @@
#--------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the ""Software""), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#--------------------------------------------------------------------------
from ..msrest import ServiceClient
from .azure_configuration import AzureConfiguration
class AzureServiceClient(ServiceClient):
def __init__(self, creds, config):
"""
Create service client.
:Args:
- config (`.Configuration`): Service configuration.
- creds (`.Authentication`): Authenticated credentials.
"""
if not config:
config = AzureConfiguration()
if not isinstance(config, AzureConfiguration):
raise TypeError("AzureServiceClient must use AzureConfiguration")
super(AzureServiceClient, self).__init__(creds, config)
class AzureChinaServiceClient(AzureServiceClient):
def __init__(self, creds, config):
super(AzureChinaServiceClient, self).__init__(creds, config)
self.config.auth_endpoint = "login.chinacloudapi.cn/"
self.resource = "https://management.core.chinacloudapi.cn/"

Просмотреть файл

@ -1,5 +1,10 @@

from runtime.msrestazure import AzureConfiguration
from runtime.msrestazure.aad import (
UserPassCredentials,
InteractiveCredentials,
ServicePrincipalCredentials,
SharedKeyCredentials)
from clientruntime.msrestazure.configuration import Configuration
from clientruntime.msrestazure.aad import UserPassCredentials
from batch_client import BatchClient
from .batch_client import BatchClient
from .batch_exception import BatchException

Просмотреть файл

@ -1,11 +1,15 @@

from clientruntime.msrest import ServiceClient, Configuration
from pool_manager import PoolManager
from runtime.msrestazure import AzureServiceClient, AzureConfiguration
from .operations.pool_operations import PoolManager
from .models import *
class BatchClient(ServiceClient):
def __init__(self, credentials, config=Configuration()):
class BatchClient(AzureServiceClient):
def __init__(self, credentials, config=AzureConfiguration()):
super(BatchClient, self).__init__(credentials, config)
self.pools = PoolManager(self, config)
self._client = ServiceClient(credentials, config)
self.pools = PoolManager(self._client)

Просмотреть файл

@ -1,5 +1,11 @@

from runtime.msrestazure import AzureConfiguration
class BatchConfiguration(AzureConfiguration):
class BatchConfiguration(Configuration):
def __init__(self, base_url=None, filepath=None):
pass
super(BatchConfiguration, self).__init__(base_url, filepath)
self.api_version = '2015-06-01.2.0'
self.request_timeout = '30'

Просмотреть файл

@ -0,0 +1,32 @@
import json
from runtime.msrestazure.azure_exceptions import CloudError
class BatchException(CloudError):
pass
class BatchBadRequestError(BatchException):
pass
class BatchEndpointNotFoundError(BatchException):
pass
class BatchOperationConflict(BatchException):
pass
class BatchStatusError(BatchException):
status_errors = { 400: BatchBadRequestError,
404: BatchEndpointNotFoundError,
409: BatchOperationConflict
}
def __new__(cls, *args, **kwargs):
response = kwargs.get('response')
if response is not None and response.status_code in cls.status_errors:
return cls.status_errors[response.status_code](*args, **kwargs)
else:
return BatchException(*args, **kargs)

Просмотреть файл

@ -1,51 +0,0 @@
from clientruntime.msrest import HTTPResponse
class BatchOperationResponse(HTTPResponse):
def __init__(self):
super(BatchOperationResponse, self).__init__()
self.headers_map.update({
'client_request_id': {'name': 'client-request-id', 'type':'str'},
'data_service_id': {'name': 'dataserviceid', 'type':'str'},
'e_tag': {'name': 'etag', 'type':'str'},
'last_modified': {'name': 'last-modified', 'type':'datetime'}
})
self._client_request_id = None
self._data_service_id = None
self._e_tag = None
self._last_modified = None
@property
def client_request_id(self):
return self._client_request_id
@client_request_id.setter
def client_request_id(self, value):
self._client_request_id = value
@property
def data_service_id(self):
return self._data_service_id
@data_service_id.setter
def data_service_id(self, value):
self._data_service_id = value
@property
def e_tag(self):
return self._e_tag
@e_tag.setter
def e_tag(self, value):
self._e_tag = value
@property
def last_modified(self):
return self._last_modified
@last_modified.setter
def last_modified(self, value):
self._last_modified = value

Просмотреть файл

Просмотреть файл

@ -2,6 +2,7 @@
class PoolState(object):
invalid = "Invalid"
active = "Active"
deleting = "Deleting"
@ -9,6 +10,7 @@ class PoolState(object):
unmapped = "Unmapped"
class AllocationState(object):
invalid = "Invalid"
steady = "Steady"
resizing = "Resizing"
@ -16,6 +18,7 @@ class AllocationState(object):
unmapped = "Unmapped"
class CertificateState(object):
invalid = "Invalid"
active = "Active"
deleting = "Deleting"
@ -23,6 +26,7 @@ class CertificateState(object):
unmapped = "Unmapped"
class CertificateFormat(object):
pfx = "Pfx"
cer = "Cer"
unmapped = "Unmapped"

Просмотреть файл

@ -1,556 +1,314 @@

from runtime.msrest.exceptions import InvalidOperationError
from runtime.msrest.utils import *
from ..batch_constants import *
from .shared import *
class BatchPoolAddResponse(BatchOperationResponse):
pass
class BatchPoolDeleteResponse(BatchOperationResponse):
pass
class BatchPoolDisableAutoScaleResponse(BatchOperationResponse):
pass
class BatchPoolEnableAutoScaleResponse(BatchOperationResponse):
pass
class BatchPoolEvaluateAutoScaleResponse(BatchOperationResponse):
pass
class BatchPoolGetResponse(BatchOperationResponse):
def __init__(self):
super(BatchPoolGetResponse, self).__init__()
self.body_map.update({
'pool': {'key':'value', 'type':'Pool'},
})
self._pool = None
@property
def pool(self):
return self._pool
@pool.setter
def pool(self, value):
self._pool = value
class BatchPoolListResponse(BatchOperationResponse):
def __init__(self):
super(BatchPoolListResponse, self).__init__()
self.body_map.update({
'pools': {'key':'value', 'type':'[Pool]'},
'next_link': {'key':'', 'type':'str'},
})
self._pools = []
self._next_link = None
@property
def next_link(self):
return self._next_link
@next_link.setter
def next_link(self, value):
self._next_link = value
@property
def pools(self):
return self._pools
@pools.setter
def pools(self, value):
self._pools = value
class BatchPoolPatchResponse(BatchOperationResponse):
pass
class BatchPoolResizeResponse(BatchOperationResponse):
pass
class BatchPoolStopResizeResponse(BatchOperationResponse):
pass
class BatchPoolUpdatePropertiesResponse(BatchOperationResponse):
pass
class BatchPoolUpgradeOSResponse(BatchOperationResponse):
pass
class BatchPoolEnableAutoScaleParameters(object):
def __init__(self):
self.attribute_map = {
'auto_scale_formula': {'key':'autoScaleFormula', 'type':'str'}
}
self._auto_scale_formula = None
@property
def auto_scale_formula(self):
return self._auto_scale_formula
@auto_scale_formula.setter
def auto_scale_formula(self, value):
self._auto_scale_formula = value
class DetailLevel(object):
def __init__(self):
self._filter_clause = None
self._select_clause = None
self._expand_clause = None
@property
def expand_clause(self):
return self._expand_clause
@expand_clause.setter
def expand_clause(self, value):
self._expand_clause = value
@property
def filter_clause(self):
return self._filter_clause
@filter_clause.setter
def filter_clause(self, value):
self._filter_clause = value
@property
def select_clause(self):
return self._select_clause
@select_clause.setter
def select_clause(self, value):
self._select_clause = value
self.filter_clause = None
self.select_clause = None
self.expand_clause = None
def get_parameters(self):
params = {}
if self.select_clause:
params['$select'] = self.select_clause
if self.expand_clause:
params['$expand'] = self.expand_clause
if self.filter_clause:
params['$filter'] = self.filter_clause
return params
class Pool(object):
def __init__(self):
class PoolParameters(object):
self.attribute_map = {
_required = ['name']
_attribute_map = {
'id':{'key':'id', 'type':'str'},
'certificate_references': {'key':'certificateReferences', 'type':'[Certificate]'},
'metadata': {'key':'metadata', 'type':'{str}'},
'name': {'key':'displayName', 'type':'str'},
'url': {'key':'url', 'type':'str'},
'e_tag': {'key':'eTag', 'type':'str'},
'last_modified': {'key':'lastModifed', 'type':'datetime'},
'creation_time': {'key':'creationTime', 'type':'datetime'},
'state': {'key':'state', 'type':'str'},
'state_transition_time': {'key':'stateTransitionTime', 'type':'datetime'},
'allocation_state': {'key':'allocationState', 'type':'str'},
'allocation_state_transition_time': {'key':'allocationStateTransitionTime', 'type':'datetime'},
'vm_size': {'key':'vmSize', 'type':'str'},
'resize_timeout': {'key':'resizeTimeout', 'type':'time'},
'resize_error': {'key':'resizeError', 'type':'ResizeError'},
'current_dedicated': {'key':'currentDedicated', 'type':'int'},
'target_dedicated': {'key':'targetDedicated', 'type':'int'},
'enable_auto_scale': {'key':'enableAutoScale', 'type':'bool'},
'auto_scale_formula': {'key':'autoScaleFormula', 'type':'str'},
'auto_scale_run': {'key':'autoScaleRun', 'type':'AutoScaleRun'},
'communication': {'key':'enableInterNodeCommunication', 'type':'str'},
'start_task': {'key':'startTask', 'type':'StartTask'},
'max_tasks_per_node': {'key':'maxTasksPerNode', 'type':'int'},
'scheduling_policy': {'key':'taskSchedulingPolicy', 'type':'TaskSchedulePolicy'},
'stats': {'key':'stats', 'type':'ResourceStats'},
'os_family': {'key':'osFamily', 'type':'str'},
'target_os_version': {'key':'targetOSVersion', 'type':'str'},
}
def __init__(self, *args, **kwargs):
self._manager = kwargs.get('manager')
self.id = None
self.certificate_references = []
self.metadata = {}
self.name = None
self.vm_size = None
self.resize_timeout = None
self.target_dedicated = None
self.enable_auto_scale = None
self.auto_scale_formula = None
self.communication = None
self.start_task = None
self.max_tasks_per_node = None
self.scheduling_policy = None
self.os_family = None
self.target_os_version = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
def add(self):
response = self._manager.add(self)
return None
class Page(object):
_required = []
_attribute_map = {
'next_link': {'key':None, 'type':'str'}
}
def __init__(self, **kwargs):
self.next_link = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
class Pool(object):
_required = ['name'] # Not sure what else needs to be here
_attribute_map = {
'id':{'key':'id', 'type':'str'},
'certificate_references': {'key':'certificateReferences', 'type':'[Certificate]'},
'metadata': {'key':'metadata', 'type':'{str}'},
'name': {'key':'displayName', 'type':'str'},
'vm_size': {'key':'vmSize', 'type':'str'},
'resize_timeout': {'key':'resizeTimeout', 'type':'time'},
'target_dedicated': {'key':'targetDedicated', 'type':'int'},
'enable_auto_scale': {'key':'enableAutoScale', 'type':'bool'},
'auto_scale_formula': {'key':'autoScaleFormula', 'type':'str'},
'communication': {'key':'enableInterNodeCommunication', 'type':'str'},
'start_task': {'key':'startTask', 'type':'StartTask'},
'max_tasks_per_node': {'key':'maxTasksPerNode', 'type':'int'},
'scheduling_policy': {'key':'taskSchedulingPolicy', 'type':'TaskSchedulePolicy'},
'os_family': {'key':'osFamily', 'type':'str'},
'target_os_version': {'key':'targetOSVersion', 'type':'str'},
'url': {'key':'url', 'type':'str'},
'e_tag': {'key':'eTag', 'type':'str'},
'last_modified': {'key':'lastModifed', 'type':'iso-date'},
'creation_time': {'key':'creationTime', 'type':'iso-date'},
'state': {'key':'state', 'type':'str'},
'state_transition_time': {'key':'stateTransitionTime', 'type':'iso-date'},
'allocation_state': {'key':'allocationState', 'type':'str'},
'allocation_state_transition_time': {'key':'allocationStateTransitionTime', 'type':'iso-date'},
'resize_error': {'key':'resizeError', 'type':'ResizeError'},
'current_dedicated': {'key':'currentDedicated', 'type':'int'},
'auto_scale_run': {'key':'autoScaleRun', 'type':'AutoScaleRun'},
'stats': {'key':'stats', 'type':'ResourceStats'},
'current_os_version': {'key':'currentOSVersion', 'type':'str'},
}
self._certificate_references = []
self._metadata = {}
self._name = None
self._url = None
self._e_tag = None
self._last_modified = None
self._creation_time = None
self._state = None
self._state_transition_time = None
self._allocation_state = None
self._allocation_state_transition_time = None
self._tvm_size = None
self._resize_timeout = None
self._resize_error = None
self._current_dedicated = None
self._target_dedicated = None
self._enable_auto_scale = None
self._auto_scale_formula = None
self._auto_scale_run = None
self._communication = None
self._start_task = None
self._max_tasks_per_tvm = None
self._scheduling_policy = None
self._stats = None
self._os_family = None
self._target_os_version = None
self._current_os_version = None
@property
def allocation_state(self):
return self._allocation_state
@allocation_state.setter
def allocation_state(self, value):
self._allocation_state = value
@property
def allocation_state_transition_time(self):
return self._allocation_state_transition_time
@allocation_state_transition_time.setter
def allocation_state_transition_time(self, value):
self._allocation_state_transition_time = value
@property
def auto_scale_formula(self):
return self._auto_scale_formula
@auto_scale_formula.setter
def auto_scale_formula(self, value):
self._auto_scale_formula = value
@property
def auto_scale_run(self):
return self._auto_scale_run
@auto_scale_run.setter
def auto_scale_run(self, value):
self._auto_scale_run = value
@property
def certificate_references(self):
return self._certificate_references
@certificate_references.setter
def certificate_references(self, value):
self._certificate_references = value
@property
def communication(self):
return self._communication
@communication.setter
def communication(self, value):
self._communication = value
@property
def creation_time(self):
return self._creation_time
@creation_time.setter
def creation_time(self, value):
self._creation_time = value
@property
def current_dedicated(self):
return self._current_dedicated
@current_dedicated.setter
def current_dedicated(self, value):
self._current_dedicated = value
@property
def current_os_version(self):
return self._current_os_version
@current_os_version.setter
def current_os_version(self, value):
self._current_os_version = value
@property
def enable_auto_scale(self):
return self._enable_auto_scale
@enable_auto_scale.setter
def enable_auto_scale(self, value):
self._enable_auto_scale = value
@property
def e_tag(self):
return self._e_tag
@e_tag.setter
def e_tag(self, value):
self._e_tag = value
@property
def last_modified(self):
return self._last_modified
@last_modified.setter
def last_modified(self, value):
self._last_modified = value
@property
def max_tasks_per_tvm(self):
return self._max_tasks_per_tvm
@max_tasks_per_tvm.setter
def max_tasks_per_tvm(self, value):
self._max_tasks_per_tvm = value
@property
def metadata(self):
return self._metadata
@metadata.setter
def metadata(self, value):
self._metadata = value
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
@property
def os_family(self):
return self._os_family
@os_family.setter
def os_family(self, value):
self._os_family = value
@property
def resize_error(self):
return self._resize_error
@resize_error.setter
def resize_error(self, value):
self._resize_error = value
@property
def resize_timeout(self):
return self._resize_timeout
@resize_timeout.setter
def resize_timeout(self, value):
self._resize_timeout = value
@property
def scheduling_policy(self):
return self._scheduling_policy
@scheduling_policy.setter
def scheduling_policy(self, value):
self._scheduling_policy = value
@property
def start_task(self):
return self._start_task
@start_task.setter
def start_task(self, value):
self._start_task = value
@property
def state(self):
return self._state
@state.setter
def state(self, value):
self._state = value
@property
def state_transition_time(self):
return self._state_transition_time
@state_transition_time.setter
def state_transition_time(self, value):
self._state_transition_time = value
@property
def stats(self):
return self._stats
@stats.setter
def stats(self, value):
self._stats = value
@property
def target_dedicated(self):
return self._target_dedicated
@target_dedicated.setter
def target_dedicated(self, value):
self._target_dedicated = value
@property
def target_os_version(self):
return self._target_os_version
@target_os_version.setter
def target_os_version(self, value):
self._target_os_version = value
@property
def tvm_size(self):
return self._tvm_size
@tvm_size.setter
def tvm_size(self, value):
self._tvm_size = value
@property
def url(self):
return self._url
@url.setter
def url(self, value):
self._url = value
def __init__(self, **kwargs):
self._manager = kwargs.get('manager')
self.id = None
self.certificate_references = []
self.metadata = {}
self.name = None
self.tvm_size = None
self.resize_timeout = None
self.target_dedicated = None
self.enable_auto_scale = None
self.auto_scale_formula = None
self.communication = None
self.start_task = None
self.max_tasks_per_tvm = None
self.scheduling_policy = None
self.os_family = None
self.target_os_version = None
self.url = None
self.e_tag = None
self.last_modified = None
self.creation_time = None
self.state = None
self.state_transition_time = None
self.allocation_state = None
self.allocation_state_transition_time = None
self.resize_error = None
self.current_dedicated = None
self.auto_scale_run = None
self.stats = None
self.current_os_version = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
def _update(self, new_pool):
for attr in self.attribute_map:
setattr(self, attr, getattr(new_pool, attr))
def update(self):
response = self._manager.get(self.id)
self._update(response.pool)
def delete(self):
response = self._manager.delete(self.id)
def disable_auto_scale(self):
response = self._manager.disable_auto_scale(self.id)
def enable_auto_scale(self, auto_scale_formula):
parameters = PoolAutoScale()
parameters.auto_scale_formula = auto_scale_formula
response = self._manager.enable_auto_scale(parameters, self.id)
def evaluate_auto_scale(self, auto_scale_formula):
parameters = PoolAutoScale()
parameters.auto_scale_formula = auto_scale_formula
response = self._manager.evaluate_auto_scale(parameters, self.id)
def patch(self, certificate_references=[], metadata={}, start_task=None):
parameters = PoolProperties()
parameters.certificate_references = certificate_references
parameters.metadata = metadata
parameters.start_task = start_task
response = self._manager.patch(parameters, self.id)
def resize(self, resize_timeout=None, target_dedicated=None, tvm_deallocation=None):
parameters = PoolResize()
paramters.resize_timeout = resize_timeout
parameters.target_dedicated = target_dedicated
parameters.tvm_deallocation_option = tvm_deallocation
response = self._manager.resize(parameters, self.id)
def stop_resize(self):
response = self._manager.stop_resize(self.id)
def update_properties(self, certificate_references=[], metadata={}, start_task=None):
parameters = PoolProperties()
parameters.certificate_references = certificate_references
parameters.metadata = metadata
parameters.start_task = start_task
response = self._manager.update_properties(parameters, self.id)
def upgrade_os(self, target_os_version):
parameters = PoolOS()
parameters.target_os_version = target_os_version
response = self._manager.upgrade_os(parameters, self.id)
class BatchPoolPatchParameters(object):
def __init__(self):
class PoolAutoScale(object):
self.attribute_map = {
'certificate_references': {'key':'autoScaleFormula', 'type':'[Certificate]'},
'metadata': {'key':'autoScaleFormula', 'type':'{str}'},
'start_task': {'key':'autoScaleFormula', 'type':'StartTask'}
_required = ['auto_scale_formula']
_attribute_map = {
'auto_scale_formula': {'key':'autoScaleFormula', 'type':'str'}
}
def __init__(self, **kwargs):
self.auto_scale_formula = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
class PoolProperties(object):
_required = []
_attribute_map = {
'certificate_references': {'key':'certificate_references', 'type':'[Certificate]'},
'metadata': {'key':'metadata', 'type':'{str}'},
'start_task': {'key':'StartTask', 'type':'StartTask'}
}
def __init__(self, **kwargs):
self._certificate_references = []
self._metadata = []
self._start_task = None
@property
def certificate_references(self):
return self._certificate_references
@certificate_references.setter
def certificate_references(self, value):
self._certificate_references = value
@property
def metadata(self):
return self._metadata
@metadata.setter
def metadata(self, value):
self._metadata = value
@property
def start_task(self):
return self._start_task
@start_task.setter
def start_task(self, value):
self._start_task = value
self.certificate_references = []
self.metadata = []
self.start_task = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
class BatchPoolResizeParameters(object):
def __init__(self):
class PoolResize(object):
self.attribute_map = {
_required = []
_attribute_map = {
'resize_timeout': {'key':'resizeTimeout', 'type':'time'},
'target_dedicated': {'key':'targetDedicated', 'type':'int'},
'tvm_deallocation_option': {'key':'tvmDeallocationOption', 'type':'str'}
}
def __init__(self, **kwargs):
self._target_dedicated = None
self._resize_timeout = None
self._tvm_deallocation_option = None
@property
def resize_timeout(self):
return self._resize_timeout
@resize_timeout.setter
def resize_timeout(self, value):
self._resize_timeout = value
@property
def target_dedicated(self):
return self._target_dedicated
@target_dedicated.setter
def target_dedicated(self, value):
self._target_dedicated = value
@property
def tvm_deallocation_option(self):
return self._tvm_deallocation_option
@tvm_deallocation_option.setter
def tvm_deallocation_option(self, value):
self._tvm_deallocation_option = value
self.target_dedicated = None
self.resize_timeout = None
self.tvm_deallocation_option = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
class BatchPoolUpdatePropertiesParameters(object):
def __init__(self):
class PoolOS(object):
self.attribute_map = {
'certificate_references': {'key':'autoScaleFormula', 'type':'[Certificate]'},
'metadata': {'key':'autoScaleFormula', 'type':'{str}'},
'start_task': {'key':'autoScaleFormula', 'type':'StartTask'}
}
self._certificate_references = []
self._metadata = []
self._start_task = None
@property
def certificate_references(self):
return self._certificate_references
@certificate_references.setter
def certificate_references(self, value):
self._certificate_references = value
@property
def metadata(self):
return self._metadata
@metadata.setter
def metadata(self, value):
self._metadata = value
@property
def start_task(self):
return self._start_task
@start_task.setter
def start_task(self, value):
self._start_task = value
_required = ['target_os_version']
class BatchPoolUpgradeOSParameters(object):
def __init__(self):
self.attribute_map = {
_attribute_map = {
'target_os_version': {'key':'targetOSVersion', 'type':'str'}
}
self._target_os_version = None
@property
def target_os_version(self):
return self._target_os_version
@target_os_version.setter
def target_os_version(self, value):
self._target_os_version = value
def __init__(self, **kwargs):
self.target_os_version = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])
class TaskSchedulePolicy(object):
_required = ['node_fill_type']
_attribute_map = {
'node_fill_type': {'key':'nodeFillType', 'type':'str'}
}
def __init__(self, **kwargs):
self.node_fill_type = None
for k in kwargs:
if hasattr(self, k):
setattr(self, k, kwargs[k])

Просмотреть файл

@ -1,111 +1,48 @@
from runtime.msrest.utils import *
class Certificate(object):
def __init__(self):
self._thumbprint = None
self._thumbprint_algorithm = None
self._url = None
self._state = None
self._state_transition_time = None
self._previous_state = None
self._previous_state_transition_time = None
self._data = None
self._certificate_format = None
self._password = None
self._public_data = None
self._delete_certificate_error = None
self.thumbprint = None
self.thumbprint_algorithm = None
self.url = None
self.state = None
self.state_transition_time = None
self.previous_state = None
self.previous_state_transition_time = None
self.data = None
self.certificate_format = None
self.password = None
self.public_data = None
self.delete_certificate_error = None
class AccessCondition(object):
@property
def certificate_format(self):
return self._certificate_format
@certificate_format.setter
def certificate_format(self, value):
self._certificate_format = value
@property
def data(self):
return self._data
@data.setter
def data(self, value):
self._data = value
@property
def delete_certificate_error(self):
return self._delete_certificate_error
@delete_certificate_error.setter
def delete_certificate_error(self, value):
self._delete_certificate_error = value
@property
def password(self):
return self._password
@password.setter
def password(self, value):
self._password = value
@property
def previous_state(self):
return self._previous_state
@previous_state.setter
def previous_state(self, value):
self._previous_state = value
@property
def previous_state_transition_time(self):
return self._previous_state_transition_time
@previous_state_transition_time.setter
def previous_state_transition_time(self, value):
self._previous_state_transition_time = value
@property
def public_data(self):
return self._public_data
@public_data.setter
def public_data(self, value):
self._public_data = value
@property
def state(self):
return self._state
@state.setter
def state(self, value):
self._state = value
@property
def state_transition_time(self):
return self._state_transition_time
@state_transition_time.setter
def state_transition_time(self, value):
self._state_transition_time = value
@property
def thumbprint(self):
return self._thumbprint
@thumbprint.setter
def thumbprint(self, value):
self._thumbprint = value
@property
def thumbprint_algorithm(self):
return self._thumbprint_algorithm
@thumbprint_algorithm.setter
def thumbprint_algorithm(self, value):
self._thumbprint_algorithm = value
@property
def url(self):
return self._url
@url.setter
def url(self, value):
self._url = value
def __init__(self, **kwargs):
self.if_modified_since_time = None
self.if_not_modified_since_time = None
self.if_match_e_tag = None
self.if_none_match_e_tag = None
def get_headers(self):
headers = {}
if self.if_match_e_tag:
headers['If-Match'] = self.if_match_e_tag
if self.if_modified_since_time:
headers['If-Modified-Since'] = format_datetime_header(
self.if_modified_since_time)
if self.if_none_match_e_tag:
headers['If-None-Match'] = self.if_none_match_e_tag
if self.if_not_modified_since_time:
headers['If-Unmodified-Since'] = format_datetime_header(
self.if_not_modified_since_time)
return headers

Просмотреть файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,452 +0,0 @@

from clientruntime.msrest.serialization import Serialized, Deserialized
from pool_operations import PoolOperations
from pool_models import *
class PoolManager(object):
def __init__(self, client):
self._ops = PoolOperations(client)
def add(self, pool):
rest_params = locals()
# Validate
if pool:
if pool.auto_scale_run:
if pool.auto_scale_run.error:
if pool.auto_scale_run.error.values:
for i in pool.auto_scale_run.error.values:
if not i.name:
raise ValueError('pool.auto_scale_run.error.values.name cannot be None.')
if not i.value:
raise ValueError('pool.auto_scale_run.error.values.value cannot be None.')
if not pool.auto_scale_run.results:
raise ValueError('pool.auto_scale_run.results cannot be None.')
if not pool.auto_scale_run.timestamp:
raise ValueError('pool.auto_scale_run.timestamp cannot be None.')
if pool.certificate_references:
for i in pool.certificate_references:
if not i.store_location:
raise ValueError('pool.certificate_references.store_location cannot be None.')
if not i.store_name:
raise ValueError('pool.certificate_references.store_name cannot be None.')
if not i.thumbprint:
raise ValueError('pool.certificate_references.thumbprint cannot be None.')
if not i.thumbprint_algorithm:
raise ValueError('pool.certificate_references.thumbprint_algorithm cannot be None.')
if not i.visibility:
raise ValueError('pool.certificate_references.visibility cannot be None.')
if pool.metadata:
for i in pool.metadata:
if not i.name:
raise ValueError('pool.metadata.name cannot be None.')
if not pool.name:
raise ValueError('pool.name cannot be None.')
if pool.resize_error:
if pool.resize_error.values:
for i in pool.resize_error.values:
if not i.name:
raise ValueError('pool.resize_error.values.name cannot be None.')
if not i.value:
raise ValueError('pool.resize_error.values.value cannot be None.')
if pool.scheduling_policy:
if not pool.scheduling_policy.tvm_fill_type:
raise ValueError('pool.scheduling_policy.tvm_fill_type cannot be None.')
if pool.start_task:
if not pool.start_task.command_line:
raise ValueError('pool.start_task.command_line cannot be None.')
if not pool.start_task.environment_settings:
raise ValueError('pool.start_task.environment_settings cannot be None.')
if pool.start_task.environment_settings:
for i in pool.start_task.environment_settings:
if not i.name:
raise ValueError('pool.start_task.environment_settings.name cannot be None.')
if (parameters.pool.start_task.resource_files is None):
raise ValueError('pool.start_task.resource_files cannot be None.')
if pool.start_task.resource_files:
for i in pool.start_task.resource_files:
if not i.blob_source:
raise ValueError('pool.start_task.resource_files.blob_source cannot be None.')
if not i.file_path:
raise ValueError('pool.start_task.resource_files.file_path cannot be None.')
content = Serialized(rest_params.pop('pool'))
try:
response = self._ops.add(content)
deserialize = Deserialized(BatchPoolAddResponse)
deserialized = deserialize(response.content)
except:
raise #TODO: exception handling
return deserialized
def delete(self, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
try:
response = self._ops.delete(**rest_params)
deserialize = Deserialized(BatchPoolDeleteResponse)
deserialized = deserialize(None)
except:
raise #TODO: exception handling
return deserialized
def disable_auto_scale(self, pool_name=None, access_condition=None):
rest_params = locals()
if not pool_name:
raise ValueError('pool_name cannot be None.')
try:
response = self._ops.disable_auto_scale(**rest_params)
deserialize = Deserialized(BatchPoolDisableAutoScaleResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def enable_auto_scale(self, parameters, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
if not parameters:
raise ValueError('parameters cannot be None.')
if not parameters.auto_scale_formula:
raise ValueError('parameters.auto_scale_formula cannot be None.')
content = Serialized(rest_params.pop('parameters'))
try:
response = self._ops.enable_auto_scale(content, **rest_params)
deserialize = Deserialized(BatchPoolEnableAutoScaleResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def evaluate_auto_scale(self, parameters, pool_name=None):
rest_params = locals()
# Validate
if (pool_name is None):
raise ValueError('pool_name cannot be None.')
if (parameters is None):
raise ValueError('parameters cannot be None.')
if (parameters.auto_scale_formula is None):
raise ValueError('parameters.auto_scale_formula cannot be None.')
content = Serialized(rest_params.pop('parameters'))
try:
response = self._ops.evaluate_auto_scale(content, **rest_params)
deserialize = Deserialized(BatchPoolEvaluateAutoScaleResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def get(self, pool_name=None, detail_level=None, access_condition=None):
rest_params = locals()
# Validate
if (pool_name is None):
raise ValueError('pool_name cannot be None.')
try:
response = self._ops.get(**rest_params)
deserialize = Deserialized(BatchPoolGetResponse)
dersialized = deserialize(response.content)
except:
raise #TODO: exception handling
return dersialized
def list(self, max_results=None, detail_level=None):
rest_params = locals()
try:
response = self._ops.list(**rest_params)
deserialize = Deserialized(BatchPoolListResponse)
dersialized = deserialize(response.content)
except:
raise #TODO: exception handling
return dersialized
def list_next(self, next_link=None):
rest_params = locals()
# Validate
if (next_link is None):
raise ValueError('next_link cannot be None.')
try:
response = self._ops.list_next(**rest_params)
deserialize = Deserialized(BatchPoolListResponse)
dersialized = deserialize(response.content)
except:
raise #TODO: exception handling
return dersialized
def patch(self, parameters, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
if not parameters:
raise ValueError('parameters cannot be None.')
if parameters.certificate_references:
for i in parameters.certificate_references:
if not i.store_location:
raise ValueError('parameters.certificate_references.store_location cannot be None.')
if not i.store_name:
raise ValueError('parameters.certificate_references.store_name cannot be None.')
if not i.thumbprint:
raise ValueError('parameters.certificate_references.thumbprint cannot be None.')
if not i.thumbprint_algorithm:
raise ValueError('parameters.certificate_references.thumbprint_algorithm cannot be None.')
if not i.visibility:
raise ValueError('parameters.certificate_references.visibility cannot be None.')
if parameters.metadata:
for i in parameters.metadata:
if not i.name:
raise ValueError('parameters.metadata.name cannot be None.')
if parameters.start_task:
if not parameters.start_task.command_line:
raise ValueError('parameters.start_task.command_line cannot be None.')
if parameters.start_task.environment_settings is None:
raise ValueError('parameters.start_task.environment_settings cannot be None.')
else:
for i in parameters.start_task.environment_settings:
if not i.name:
raise ValueError('parameters.start_task.environment_settings.name cannot be None.')
if parameters.start_task.resource_files is None:
raise ValueError('parameters.start_task.resource_files cannot be None.')
else:
for i in parameters.start_task.resource_files:
if not i.blob_source:
raise ValueError('parameters.start_task.resource_files.blob_source cannot be None.')
if not i.file_path:
raise ValueError('parameters.start_task.resource_files.file_path cannot be None.')
content = Serialized(rest_params.pop('parameters'))
try:
response = self._ops.patch(content, **rest_params)
deserialize = Deserialized(BatchPoolPatchResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def resize(self, parameters, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
if not parameters:
raise ValueError('parameters cannot be None.')
content = Serialized(rest_params.pop('parameters'))
try:
response = self._ops.resize(content, **rest_params)
deserialize = Deserialized(BatchPoolResizeResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def stop_resize(self, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
try:
response = self._ops.stop_resize(**rest_params)
deserialize = Deserialized(BatchPoolStopResizeResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def update_properties(self, properties, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
if not properties:
raise ValueError('properties cannot be None.')
if parameters.certificate_references:
for i in parameters.certificate_references:
if not i.store_location:
raise ValueError('parameters.certificate_references.store_location cannot be None.')
if not i.store_name:
raise ValueError('parameters.certificate_references.store_name cannot be None.')
if not i.thumbprint:
raise ValueError('parameters.certificate_references.thumbprint cannot be None.')
if not i.thumbprint_algorithm:
raise ValueError('parameters.certificate_references.thumbprint_algorithm cannot be None.')
if not i.visibility:
raise ValueError('parameters.certificate_references.visibility cannot be None.')
if parameters.metadata:
for i in parameters.metadata:
if not i.name:
raise ValueError('parameters.metadata.name cannot be None.')
if parameters.start_task:
if not parameters.start_task.command_line:
raise ValueError('parameters.start_task.command_line cannot be None.')
if parameters.start_task.environment_settings is None:
raise ValueError('parameters.start_task.environment_settings cannot be None.')
else:
for i in parameters.start_task.environment_settings:
if not i.name:
raise ValueError('parameters.start_task.environment_settings.name cannot be None.')
if parameters.start_task.resource_files is None:
raise ValueError('parameters.start_task.resource_files cannot be None.')
else:
for i in parameters.start_task.resource_files:
if not i.blob_source:
raise ValueError('parameters.start_task.resource_files.blob_source cannot be None.')
if not i.file_path:
raise ValueError('parameters.start_task.resource_files.file_path cannot be None.')
content = Serialized(rest_params.pop('properties'))
try:
response = self._ops.update_properties(content, **rest_params)
deserialize = Deserialized(BatchPoolUpdatePropertiesResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized
def upgrade_os(self, parameters, pool_name=None, access_condition=None):
rest_params = locals()
# Validate
if not pool_name:
raise ValueError('pool_name cannot be None.')
if not parameters:
raise ValueError('parameters cannot be None.')
if not parameters.target_os_version:
raise ValueError('parameters.target_os_version cannot be None.')
content = Serialized(rest_params.pop('parameters'))
try:
response = self._ops.upgrade_os(content, **rest_params)
deserialize = Deserialized(BatchPoolUpgradeOSResponse)
dersialized = deserialize(None)
except:
raise #TODO: exception handling
return dersialized

Просмотреть файл

@ -1,14 +1,44 @@

from batch_client import BatchClient, UserPassCredentials, Configuration
creds = UserPassCredentials(user, passw)
config = Configuration()
from sample import BatchClient, BatchException
from sample import SharedKeyCredentials
from sample import AzureConfiguration
# Configure service
# config.url =
# config.retry_policy =
from uuid import uuid4
batch_url = "" # Insert Batch service URL
account = "" # Insert account name
key = "" # Insert shared key
creds = SharedKeyCredentials(account, key)
config = AzureConfiguration(batch_url)
config.log_dir = "D:\\TestData"
config.log_level = 10
client = BatchClient(creds, config)
pools = client.pools.list()
new_pool = client.pools.Pool()
new_pool.target_size = 10
client.pools.add(new_pool)
try:
new_pool = client.pools.pool(name="MyTestPool")
new_pool.vm_size="small"
new_pool.os_family ="4"
new_pool.target_dedicated = 1
new_pool.id = str(uuid4())
client.pools.add(new_pool)
except BatchException as err:
print("{0}: {1}".format(err.error, err.message))
try:
pools = client.pools.list()
all_pools = [p for p in pools]
first_pool = all_pools[0]
print(first_pool.os_family)
print(first_pool.name)
print(first_pool.scheduling_policy.node_fill_type)
first_pool.delete()
except BatchException as err:
print("{0}: {1}".format(err.error, err.message))

Просмотреть файл

@ -6,12 +6,13 @@
<ProjectGuid>671bdd39-3489-484e-b489-8dfb4db226e2</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>batch_configuration.py</StartupFile>
<SearchPath>
</SearchPath>
<SearchPath>.</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<Name>sample_client</Name>
<RootNamespace>sample_client</RootNamespace>
<InterpreterId>{c713ae69-eff3-4814-a3dc-0ee4bb342268}</InterpreterId>
<InterpreterVersion>3.5</InterpreterVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
@ -26,10 +27,10 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\batch_configuration.py" />
<Compile Include="sample\batch_response.py">
<Compile Include="sample\batch_exception.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\models\constants.py">
<Compile Include="sample\models\enums.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\models\pool_models.py">
@ -38,10 +39,13 @@
<Compile Include="sample\models\shared.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\models\__init__.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\operations\pool_operations.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\pool_manager.py">
<Compile Include="sample\operations\__init__.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="sample\test_script.py">
@ -56,6 +60,30 @@
<Folder Include="sample\models\" />
<Folder Include="sample\operations\" />
</ItemGroup>
<ItemGroup>
<Interpreter Include="..\..\..\PythonEnv\Python27-64-ENV\">
<Id>{d84f20fd-0008-4984-be36-039ba1375663}</Id>
<BaseInterpreter>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</BaseInterpreter>
<Version>2.7</Version>
<Description>Python27-64-ENV (Python 64-bit 2.7)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>Amd64</Architecture>
</Interpreter>
<Interpreter Include="..\..\..\PythonEnv\Python35-64-ENV\">
<Id>{c713ae69-eff3-4814-a3dc-0ee4bb342268}</Id>
<BaseInterpreter>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</BaseInterpreter>
<Version>3.5</Version>
<Description>Python35-64-ENV (Python 64-bit 3.5)</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<LibraryPath>Lib\</LibraryPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>Amd64</Architecture>
</Interpreter>
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<PtvsTargetsFile>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets</PtvsTargetsFile>