blob: bb40d59e3c938ea0004f2a8a1fdc40b2e8ea16ce [file] [log] [blame]
Soren Hansenbc1d3a02011-09-08 13:33:17 +02001import json
Soren Hansenbc1d3a02011-09-08 13:33:17 +02002
3import kong.common.http
4from kong import exceptions
5
6
7class API(kong.common.http.Client):
8 """Barebones Nova HTTP API client."""
9
10 def __init__(self, host, port, base_url, user, api_key, project_id=''):
11 """Initialize Nova HTTP API client.
12
13 :param host: Hostname/IP of the Nova API to test.
14 :param port: Port of the Nova API to test.
15 :param base_url: Version identifier (normally /v1.0 or /v1.1)
16 :param user: The username to use for tests.
17 :param api_key: The API key of the user.
18 :returns: None
19
20 """
21 super(API, self).__init__(host, port, base_url)
22 self.user = user
23 self.api_key = api_key
24 self.project_id = project_id
Dolph Mathewsc3bc0962011-11-13 21:05:19 -060025 # Default to same as base_url, but will be changed for auth
Soren Hansenbc1d3a02011-09-08 13:33:17 +020026 self.management_url = self.base_url
27
28 def authenticate(self, user, api_key, project_id):
29 """Request and return an authentication token from Nova.
30
31 :param user: The username we're authenticating.
32 :param api_key: The API key for the user we're authenticating.
33 :returns: Authentication token (string)
34 :raises: KeyError if authentication fails.
35
36 """
37 headers = {
38 'X-Auth-User': user,
39 'X-Auth-Key': api_key,
40 'X-Auth-Project-Id': project_id,
41 }
42 resp, body = super(API, self).request('GET', '', headers=headers,
43 base_url=self.base_url)
44
45 try:
46 self.management_url = resp['x-server-management-url']
47 return resp['x-auth-token']
48 except KeyError:
49 print "Failed to authenticate user"
50 raise
51
52 def _wait_for_entity_status(self, url, entity_name, status, **kwargs):
53 """Poll the provided url until expected entity status is returned"""
54
55 def check_response(resp, body):
56 try:
57 data = json.loads(body)
58 return data[entity_name]['status'] == status
59 except (ValueError, KeyError):
60 return False
61
62 try:
63 self.poll_request('GET', url, check_response, **kwargs)
64 except exceptions.TimeoutException:
65 msg = "%s failed to reach status %s" % (entity_name, status)
66 raise AssertionError(msg)
67
68 def wait_for_server_status(self, server_id, status='ACTIVE', **kwargs):
69 """Wait for the server status to be equal to the status passed in.
70
71 :param server_id: Server ID to query.
72 :param status: The status string to look for.
73 :returns: None
74 :raises: AssertionError if request times out
75
76 """
77 url = '/servers/%s' % server_id
78 return self._wait_for_entity_status(url, 'server', status, **kwargs)
79
80 def wait_for_image_status(self, image_id, status='ACTIVE', **kwargs):
81 """Wait for the image status to be equal to the status passed in.
82
83 :param image_id: Image ID to query.
84 :param status: The status string to look for.
85 :returns: None
86 :raises: AssertionError if request times out
87
88 """
89 url = '/images/%s' % image_id
90 return self._wait_for_entity_status(url, 'image', status, **kwargs)
91
92 def request(self, method, url, **kwargs):
93 """Generic HTTP request on the Nova API.
94
95 :param method: Request verb to use (GET, PUT, POST, etc.)
96 :param url: The API resource to request.
97 :param kwargs: Additional keyword arguments to pass to the request.
98 :returns: HTTP response object.
99
100 """
101 headers = kwargs.get('headers', {})
102 project_id = kwargs.get('project_id', self.project_id)
103
104 headers['X-Auth-Token'] = self.authenticate(self.user, self.api_key,
Dolph Mathewsc3bc0962011-11-13 21:05:19 -0600105 project_id)
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200106 kwargs['headers'] = headers
107 return super(API, self).request(method, url, **kwargs)
108
109 def get_server(self, server_id):
110 """Fetch a server by id
111
112 :param server_id: dict of server attributes
113 :returns: dict of server attributes
114 :raises: ServerNotFound if server does not exist
115
116 """
117 resp, body = self.request('GET', '/servers/%s' % server_id)
118 try:
119 assert resp['status'] == '200'
120 data = json.loads(body)
121 return data['server']
122 except (AssertionError, ValueError, TypeError, KeyError):
123 raise exceptions.ServerNotFound(server_id)
124
125 def create_server(self, entity):
126 """Attempt to create a new server.
127
128 :param entity: dict of server attributes
129 :returns: dict of server attributes after creation
130 :raises: AssertionError if server creation fails
131
132 """
133 post_body = json.dumps({
134 'server': entity,
135 })
136
137 resp, body = self.request('POST', '/servers', body=post_body)
138 try:
139 assert resp['status'] == '202'
140 data = json.loads(body)
141 return data['server']
142 except (AssertionError, ValueError, TypeError, KeyError):
143 raise AssertionError("Failed to create server")
144
145 def delete_server(self, server_id):
146 """Attempt to delete a server.
147
148 :param server_id: server identifier
149 :returns: None
150
151 """
152 url = '/servers/%s' % server_id
153 response, body = self.request('DELETE', url)