зеркало из https://github.com/Azure/autorest.git
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:
Родитель
b43ac03103
Коммит
3aa5018b51
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче