PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/nova/tests/integrated/api/client.py

https://github.com/santhoshkumartw/openstack-nova
Python | 263 lines | 206 code | 36 blank | 21 comment | 19 complexity | 83f648d67b881e6e7928413720c2c8e6 MD5 | raw file
  1. # vim: tabstop=4 shiftwidth=4 softtabstop=4
  2. # Copyright (c) 2011 Justin Santa Barbara
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # 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, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. import json
  16. import httplib
  17. import urlparse
  18. from nova import log as logging
  19. LOG = logging.getLogger('nova.tests.api')
  20. class OpenStackApiException(Exception):
  21. def __init__(self, message=None, response=None):
  22. self.response = response
  23. if not message:
  24. message = 'Unspecified error'
  25. if response:
  26. _status = response.status
  27. _body = response.read()
  28. message = _('%(message)s\nStatus Code: %(_status)s\n'
  29. 'Body: %(_body)s') % locals()
  30. super(OpenStackApiException, self).__init__(message)
  31. class OpenStackApiAuthenticationException(OpenStackApiException):
  32. def __init__(self, response=None, message=None):
  33. if not message:
  34. message = _("Authentication error")
  35. super(OpenStackApiAuthenticationException, self).__init__(message,
  36. response)
  37. class OpenStackApiNotFoundException(OpenStackApiException):
  38. def __init__(self, response=None, message=None):
  39. if not message:
  40. message = _("Item not found")
  41. super(OpenStackApiNotFoundException, self).__init__(message, response)
  42. class TestOpenStackClient(object):
  43. """Simple OpenStack API Client.
  44. This is a really basic OpenStack API client that is under our control,
  45. so we can make changes / insert hooks for testing
  46. """
  47. def __init__(self, auth_user, auth_key, auth_uri):
  48. super(TestOpenStackClient, self).__init__()
  49. self.auth_result = None
  50. self.auth_user = auth_user
  51. self.auth_key = auth_key
  52. self.auth_uri = auth_uri
  53. def request(self, url, method='GET', body=None, headers=None):
  54. _headers = {'Content-Type': 'application/json'}
  55. _headers.update(headers or {})
  56. parsed_url = urlparse.urlparse(url)
  57. port = parsed_url.port
  58. hostname = parsed_url.hostname
  59. scheme = parsed_url.scheme
  60. if scheme == 'http':
  61. conn = httplib.HTTPConnection(hostname,
  62. port=port)
  63. elif scheme == 'https':
  64. conn = httplib.HTTPSConnection(hostname,
  65. port=port)
  66. else:
  67. raise OpenStackApiException("Unknown scheme: %s" % url)
  68. relative_url = parsed_url.path
  69. if parsed_url.query:
  70. relative_url = relative_url + parsed_url.query
  71. LOG.info(_("Doing %(method)s on %(relative_url)s") % locals())
  72. if body:
  73. LOG.info(_("Body: %s") % body)
  74. conn.request(method, relative_url, body, _headers)
  75. response = conn.getresponse()
  76. return response
  77. def _authenticate(self):
  78. if self.auth_result:
  79. return self.auth_result
  80. auth_uri = self.auth_uri
  81. headers = {'X-Auth-User': self.auth_user,
  82. 'X-Auth-Key': self.auth_key}
  83. response = self.request(auth_uri,
  84. headers=headers)
  85. http_status = response.status
  86. LOG.debug(_("%(auth_uri)s => code %(http_status)s") % locals())
  87. if http_status == 401:
  88. raise OpenStackApiAuthenticationException(response=response)
  89. auth_headers = {}
  90. for k, v in response.getheaders():
  91. auth_headers[k] = v
  92. self.auth_result = auth_headers
  93. return self.auth_result
  94. def api_request(self, relative_uri, check_response_status=None, **kwargs):
  95. auth_result = self._authenticate()
  96. # NOTE(justinsb): httplib 'helpfully' converts headers to lower case
  97. base_uri = auth_result['x-server-management-url']
  98. full_uri = base_uri + relative_uri
  99. headers = kwargs.setdefault('headers', {})
  100. headers['X-Auth-Token'] = auth_result['x-auth-token']
  101. response = self.request(full_uri, **kwargs)
  102. http_status = response.status
  103. LOG.debug(_("%(relative_uri)s => code %(http_status)s") % locals())
  104. if check_response_status:
  105. if not http_status in check_response_status:
  106. if http_status == 404:
  107. raise OpenStackApiNotFoundException(response=response)
  108. else:
  109. raise OpenStackApiException(
  110. message=_("Unexpected status code"),
  111. response=response)
  112. return response
  113. def _decode_json(self, response):
  114. body = response.read()
  115. LOG.debug(_("Decoding JSON: %s") % (body))
  116. if body:
  117. return json.loads(body)
  118. else:
  119. return ""
  120. def api_get(self, relative_uri, **kwargs):
  121. kwargs.setdefault('check_response_status', [200])
  122. response = self.api_request(relative_uri, **kwargs)
  123. return self._decode_json(response)
  124. def api_post(self, relative_uri, body, **kwargs):
  125. kwargs['method'] = 'POST'
  126. if body:
  127. headers = kwargs.setdefault('headers', {})
  128. headers['Content-Type'] = 'application/json'
  129. kwargs['body'] = json.dumps(body)
  130. kwargs.setdefault('check_response_status', [200, 202])
  131. response = self.api_request(relative_uri, **kwargs)
  132. return self._decode_json(response)
  133. def api_put(self, relative_uri, body, **kwargs):
  134. kwargs['method'] = 'PUT'
  135. if body:
  136. headers = kwargs.setdefault('headers', {})
  137. headers['Content-Type'] = 'application/json'
  138. kwargs['body'] = json.dumps(body)
  139. kwargs.setdefault('check_response_status', [200, 202, 204])
  140. response = self.api_request(relative_uri, **kwargs)
  141. return self._decode_json(response)
  142. def api_delete(self, relative_uri, **kwargs):
  143. kwargs['method'] = 'DELETE'
  144. kwargs.setdefault('check_response_status', [200, 202, 204])
  145. return self.api_request(relative_uri, **kwargs)
  146. def get_server(self, server_id):
  147. return self.api_get('/servers/%s' % server_id)['server']
  148. def get_servers(self, detail=True):
  149. rel_url = '/servers/detail' if detail else '/servers'
  150. return self.api_get(rel_url)['servers']
  151. def post_server(self, server):
  152. return self.api_post('/servers', server)['server']
  153. def put_server(self, server_id, server):
  154. return self.api_put('/servers/%s' % server_id, server)
  155. def post_server_action(self, server_id, data):
  156. return self.api_post('/servers/%s/action' % server_id, data)
  157. def delete_server(self, server_id):
  158. return self.api_delete('/servers/%s' % server_id)
  159. def get_image(self, image_id):
  160. return self.api_get('/images/%s' % image_id)['image']
  161. def get_images(self, detail=True):
  162. rel_url = '/images/detail' if detail else '/images'
  163. return self.api_get(rel_url)['images']
  164. def post_image(self, image):
  165. return self.api_post('/images', image)['image']
  166. def delete_image(self, image_id):
  167. return self.api_delete('/images/%s' % image_id)
  168. def get_flavor(self, flavor_id):
  169. return self.api_get('/flavors/%s' % flavor_id)['flavor']
  170. def get_flavors(self, detail=True):
  171. rel_url = '/flavors/detail' if detail else '/flavors'
  172. return self.api_get(rel_url)['flavors']
  173. def post_flavor(self, flavor):
  174. return self.api_post('/flavors', flavor)['flavor']
  175. def delete_flavor(self, flavor_id):
  176. return self.api_delete('/flavors/%s' % flavor_id)
  177. def get_volume(self, volume_id):
  178. return self.api_get('/os-volumes/%s' % volume_id)['volume']
  179. def get_volumes(self, detail=True):
  180. rel_url = '/os-volumes/detail' if detail else '/os-volumes'
  181. return self.api_get(rel_url)['volumes']
  182. def post_volume(self, volume):
  183. return self.api_post('/os-volumes', volume)['volume']
  184. def delete_volume(self, volume_id):
  185. return self.api_delete('/os-volumes/%s' % volume_id)
  186. def get_server_volume(self, server_id, attachment_id):
  187. return self.api_get('/servers/%s/os-volume_attachments/%s' %
  188. (server_id, attachment_id))['volumeAttachment']
  189. def get_server_volumes(self, server_id):
  190. return self.api_get('/servers/%s/os-volume_attachments' %
  191. (server_id))['volumeAttachments']
  192. def post_server_volume(self, server_id, volume_attachment):
  193. return self.api_post('/servers/%s/os-volume_attachments' %
  194. (server_id), volume_attachment)['volumeAttachment']
  195. def delete_server_volume(self, server_id, attachment_id):
  196. return self.api_delete('/servers/%s/os-volume_attachments/%s' %
  197. (server_id, attachment_id))