/libcloud/common/cloudstack.py

https://github.com/raweng/libcloud · Python · 121 lines · 86 code · 20 blank · 15 comment · 2 complexity · 2c4f95acb62be9f801c16e6daf9c51c6 MD5 · raw file

  1. # Licensed to the Apache Software Foundation (ASF) under one or more
  2. # contributor license agreements. See the NOTICE file distributed with
  3. # this work for additional information regarding copyright ownership.
  4. # The ASF licenses this file to You under the Apache License, Version 2.0
  5. # (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import base64
  16. import hashlib
  17. import hmac
  18. from libcloud.utils.py3 import urlencode
  19. from libcloud.utils.py3 import b
  20. from libcloud.common.base import ConnectionUserAndKey, PollingConnection
  21. from libcloud.common.base import JsonResponse
  22. from libcloud.common.types import MalformedResponseError
  23. class CloudStackResponse(JsonResponse):
  24. pass
  25. class CloudStackConnection(ConnectionUserAndKey, PollingConnection):
  26. responseCls = CloudStackResponse
  27. poll_interval = 1
  28. request_method = '_sync_request'
  29. timeout = 600
  30. ASYNC_PENDING = 0
  31. ASYNC_SUCCESS = 1
  32. ASYNC_FAILURE = 2
  33. def _make_signature(self, params):
  34. signature = [(k.lower(), v) for k, v in list(params.items())]
  35. signature.sort(key=lambda x: x[0])
  36. signature = urlencode(signature)
  37. signature = signature.lower().replace('+', '%20')
  38. signature = hmac.new(b(self.key), msg=b(signature),
  39. digestmod=hashlib.sha1)
  40. return base64.b64encode(b(signature.digest()))
  41. def add_default_params(self, params):
  42. params['apiKey'] = self.user_id
  43. params['response'] = 'json'
  44. return params
  45. def pre_connect_hook(self, params, headers):
  46. params['signature'] = self._make_signature(params)
  47. return params, headers
  48. def _async_request(self, command, **kwargs):
  49. context = {'command': command}
  50. context.update(kwargs)
  51. result = super(CloudStackConnection, self).async_request(action=None,
  52. params=None,
  53. data=None,
  54. headers=None,
  55. method=None,
  56. context=context)
  57. return result['jobresult']
  58. def get_request_kwargs(self, action, params=None, data='', headers=None,
  59. method='GET', context=None):
  60. return context
  61. def get_poll_request_kwargs(self, response, context, request_kwargs):
  62. job_id = response['jobid']
  63. kwargs = {'command': 'queryAsyncJobResult', 'jobid': job_id}
  64. return kwargs
  65. def has_completed(self, response):
  66. status = response.get('jobstatus', self.ASYNC_PENDING)
  67. if status == self.ASYNC_FAILURE:
  68. raise Exception(status)
  69. return status == self.ASYNC_SUCCESS
  70. def _sync_request(self, command, **kwargs):
  71. """This method handles synchronous calls which are generally fast
  72. information retrieval requests and thus return 'quickly'."""
  73. kwargs['command'] = command
  74. result = self.request(self.driver.path, params=kwargs)
  75. command = command.lower() + 'response'
  76. if command not in result.object:
  77. raise MalformedResponseError(
  78. "Unknown response format",
  79. body=result.body,
  80. driver=self.driver)
  81. result = result.object[command]
  82. return result
  83. class CloudStackDriverMixIn(object):
  84. host = None
  85. path = None
  86. connectionCls = CloudStackConnection
  87. def __init__(self, key, secret=None, secure=True, host=None, port=None):
  88. host = host or self.host
  89. super(CloudStackDriverMixIn, self).__init__(key, secret, secure, host,
  90. port)
  91. def _sync_request(self, command, **kwargs):
  92. return self.connection._sync_request(command, **kwargs)
  93. def _async_request(self, command, **kwargs):
  94. return self.connection._async_request(command, **kwargs)