blob: 8824f922d0d3d02c12a097ae844ae297669977f4 [file] [log] [blame]
Soren Hansenbc1d3a02011-09-08 13:33:17 +02001
2import base64
3import json
4import os
5
Soren Hansenbc1d3a02011-09-08 13:33:17 +02006from kong import openstack
7from kong import exceptions
Soren Hansen6adacc82011-09-09 13:34:35 +02008from kong import tests
Soren Hansenbc1d3a02011-09-08 13:33:17 +02009from kong.common import ssh
10
11
Soren Hansen6adacc82011-09-09 13:34:35 +020012class ServersTest(tests.FunctionalTest):
Soren Hansen4480f602011-09-09 16:12:35 +020013 def setUp(self):
Soren Hansen6adacc82011-09-09 13:34:35 +020014 super(ServersTest, self).setUp()
Soren Hansend6b047a2011-09-09 13:39:32 +020015 self.os = openstack.Manager(self.nova)
Soren Hansena86180a2011-09-09 16:22:26 +020016 self.image_ref = self.glance['image_id']
17 self.flavor_ref = self.nova['flavor_ref']
18 self.ssh_timeout = self.nova['ssh_timeout']
19 self.build_timeout = self.nova['build_timeout']
Soren Hansenbc1d3a02011-09-08 13:33:17 +020020
21 def _assert_server_entity(self, server):
22 actual_keys = set(server.keys())
23 expected_keys = set((
24 'id',
25 'name',
26 'hostId',
27 'status',
28 'metadata',
29 'addresses',
30 'links',
31 'progress',
32 'image',
33 'flavor',
34 'created',
35 'updated',
36 'accessIPv4',
37 'accessIPv6',
38
39 #KNOWN-ISSUE lp804093
40 'uuid',
41
42 ))
43 self.assertTrue(expected_keys <= actual_keys)
44
45 server_id = str(server['id'])
Soren Hansena86180a2011-09-09 16:22:26 +020046 host = self.nova['host']
47 port = self.nova['port']
Soren Hansenbc1d3a02011-09-08 13:33:17 +020048 api_url = '%s:%s' % (host, port)
Soren Hansena86180a2011-09-09 16:22:26 +020049 base_url = os.path.join(api_url, self.nova['apiver'])
Soren Hansenbc1d3a02011-09-08 13:33:17 +020050
51 self_link = 'http://' + os.path.join(base_url,
Soren Hansena86180a2011-09-09 16:22:26 +020052# self.os.config.nova.project_id,
Soren Hansenbc1d3a02011-09-08 13:33:17 +020053 'servers', server_id)
54 bookmark_link = 'http://' + os.path.join(api_url,
Soren Hansena86180a2011-09-09 16:22:26 +020055# self.os.config.nova.project_id,
Soren Hansenbc1d3a02011-09-08 13:33:17 +020056 'servers', server_id)
57
58 expected_links = [
59 {
60 'rel': 'self',
61 'href': self_link,
62 },
63 {
64 'rel': 'bookmark',
65 'href': bookmark_link,
66 },
67 ]
68
69 self.assertEqual(server['links'], expected_links)
70
71 def test_build_server(self):
72 """Build a server"""
73
74 expected_server = {
75 'name': 'testserver',
76 'metadata': {
77 'key1': 'value1',
78 'key2': 'value2',
79 },
80 'imageRef': self.image_ref,
81 'flavorRef': self.flavor_ref,
82 }
83
84 post_body = json.dumps({'server': expected_server})
85 response, body = self.os.nova.request('POST',
86 '/servers',
87 body=post_body)
88
89 self.assertEqual(response.status, 202)
90
91 _body = json.loads(body)
92 self.assertEqual(_body.keys(), ['server'])
93 created_server = _body['server']
94
95 admin_pass = created_server.pop('adminPass')
96 self._assert_server_entity(created_server)
97 self.assertEqual(expected_server['name'], created_server['name'])
98 self.assertEqual(expected_server['metadata'],
99 created_server['metadata'])
100
101 self.os.nova.wait_for_server_status(created_server['id'],
102 'ACTIVE',
103 timeout=self.build_timeout)
104
105 server = self.os.nova.get_server(created_server['id'])
106
107 # Find IP of server
108 try:
109 (_, network) = server['addresses'].popitem()
110 ip = network[0]['addr']
111 except KeyError:
112 self.fail("Failed to retrieve IP address from server entity")
113
114 # Assert password works
115 client = ssh.Client(ip, 'root', admin_pass, self.ssh_timeout)
116 self.assertTrue(client.test_connection_auth())
117
118 self.os.nova.delete_server(server['id'])
Soren Hansenfce58c52011-09-09 16:07:13 +0200119 test_build_server.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200120
121 def test_build_server_with_file(self):
122 """Build a server with an injected file"""
123
124 file_contents = 'testing'
125
126 expected_server = {
127 'name': 'testserver',
128 'metadata': {
129 'key1': 'value1',
130 'key2': 'value2',
131 },
132 'personality': [
133 {
134 'path': '/etc/test.txt',
135 'contents': base64.b64encode(file_contents),
136 },
137 ],
138 'imageRef': self.image_ref,
139 'flavorRef': self.flavor_ref,
140 }
141
142 post_body = json.dumps({'server': expected_server})
143 response, body = self.os.nova.request('POST',
144 '/servers',
145 body=post_body)
146
147 self.assertEqual(response.status, 202)
148
149 _body = json.loads(body)
150 self.assertEqual(_body.keys(), ['server'])
151 created_server = _body['server']
152
153 admin_pass = created_server.pop('adminPass', None)
154 self._assert_server_entity(created_server)
155 self.assertEqual(expected_server['name'], created_server['name'])
156 self.assertEqual(expected_server['metadata'],
157 created_server['metadata'])
158
159 self.os.nova.wait_for_server_status(created_server['id'],
160 'ACTIVE',
161 timeout=self.build_timeout)
162
163 server = self.os.nova.get_server(created_server['id'])
164
165 # Find IP of server
166 try:
167 (_, network) = server['addresses'].popitem()
168 ip = network[0]['addr']
169 except KeyError:
170 self.fail("Failed to retrieve IP address from server entity")
171
172 # Assert injected file is on instance, also verifying password works
173 client = ssh.Client(ip, 'root', admin_pass, self.ssh_timeout)
174 injected_file = client.exec_command('cat /etc/test.txt')
175 self.assertEqual(injected_file, file_contents)
176
177 self.os.nova.delete_server(server['id'])
Soren Hansenfce58c52011-09-09 16:07:13 +0200178 test_build_server_with_file.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200179
180 def test_build_server_with_password(self):
181 """Build a server with a password"""
182
183 server_password = 'testpwd'
184
185 expected_server = {
186 'name': 'testserver',
187 'metadata': {
188 'key1': 'value1',
189 'key2': 'value2',
190 },
191 'adminPass': server_password,
192 'imageRef': self.image_ref,
193 'flavorRef': self.flavor_ref,
194 }
195
196 post_body = json.dumps({'server': expected_server})
197 response, body = self.os.nova.request('POST',
198 '/servers',
199 body=post_body)
200
201 self.assertEqual(response.status, 202)
202
203 _body = json.loads(body)
204 self.assertEqual(_body.keys(), ['server'])
205 created_server = _body['server']
206
207 admin_pass = created_server.pop('adminPass', None)
208 self._assert_server_entity(created_server)
209 self.assertEqual(expected_server['name'], created_server['name'])
210 self.assertEqual(expected_server['adminPass'], admin_pass)
211 self.assertEqual(expected_server['metadata'],
212 created_server['metadata'])
213
214 self.os.nova.wait_for_server_status(created_server['id'],
215 'ACTIVE',
216 timeout=self.build_timeout)
217
218 server = self.os.nova.get_server(created_server['id'])
219
220 # Find IP of server
221 try:
222 (_, network) = server['addresses'].popitem()
223 ip = network[0]['addr']
224 except KeyError:
225 self.fail("Failed to retrieve IP address from server entity")
226
227 # Assert password was set to that in request
228 client = ssh.Client(ip, 'root', server_password, self.ssh_timeout)
229 self.assertTrue(client.test_connection_auth())
230
231 self.os.nova.delete_server(server['id'])
Soren Hansenfce58c52011-09-09 16:07:13 +0200232 test_build_server_with_password.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200233
234 def test_delete_server_building(self):
235 """Delete a server while building"""
236
237 # Make create server request
238 server = {
239 'name' : 'testserver',
240 'imageRef' : self.image_ref,
241 'flavorRef' : self.flavor_ref,
242 }
243 created_server = self.os.nova.create_server(server)
244
245 # Server should immediately be accessible, but in have building status
246 server = self.os.nova.get_server(created_server['id'])
247 self.assertEqual(server['status'], 'BUILD')
248
249 self.os.nova.delete_server(created_server['id'])
250
251 # Poll server until deleted
252 try:
253 url = '/servers/%s' % created_server['id']
254 self.os.nova.poll_request_status('GET', url, 404)
255 except exceptions.TimeoutException:
256 self.fail("Server deletion timed out")
Soren Hansenfce58c52011-09-09 16:07:13 +0200257 test_delete_server_building.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200258
259 def test_delete_server_active(self):
260 """Delete a server after fully built"""
261
262 expected_server = {
263 'name' : 'testserver',
264 'imageRef' : self.image_ref,
265 'flavorRef' : self.flavor_ref,
266 }
267
268 created_server = self.os.nova.create_server(expected_server)
269 server_id = created_server['id']
270
271 self.os.nova.wait_for_server_status(server_id,
272 'ACTIVE',
273 timeout=self.build_timeout)
274
275 self.os.nova.delete_server(server_id)
276
277 # Poll server until deleted
278 try:
279 url = '/servers/%s' % server_id
280 self.os.nova.poll_request_status('GET', url, 404)
281 except exceptions.TimeoutException:
282 self.fail("Server deletion timed out")
Soren Hansenfce58c52011-09-09 16:07:13 +0200283 test_delete_server_active.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200284
285 def test_update_server_name(self):
286 """Change the name of a server"""
287
288 expected_server = {
289 'name' : 'testserver',
290 'imageRef' : self.image_ref,
291 'flavorRef' : self.flavor_ref,
292 }
293
294 created_server = self.os.nova.create_server(expected_server)
295
296 self.assertTrue(expected_server['name'], created_server['name'])
297 server_id = created_server['id']
298
299 # Wait for it to be built
300 self.os.nova.wait_for_server_status(server_id,
301 'ACTIVE',
302 timeout=self.build_timeout)
303
304 # Update name
305 new_server = {'name': 'updatedtestserver'}
306 put_body = json.dumps({
307 'server': new_server,
308 })
309 url = '/servers/%s' % server_id
310 resp, body = self.os.nova.request('PUT', url, body=put_body)
311
312 self.assertEqual(resp.status, 200)
313 data = json.loads(body)
314 self.assertEqual(data.keys(), ['server'])
315 self._assert_server_entity(data['server'])
316 self.assertEqual('updatedtestserver', data['server']['name'])
317
318 # Get Server information
319 resp, body = self.os.nova.request('GET', '/servers/%s' % server_id)
320 self.assertEqual(200, resp.status)
321 data = json.loads(body)
322 self.assertEqual(data.keys(), ['server'])
323 self._assert_server_entity(data['server'])
324 self.assertEqual('updatedtestserver', data['server']['name'])
325
326 self.os.nova.delete_server(server_id)
Soren Hansenfce58c52011-09-09 16:07:13 +0200327 test_update_server_name.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200328
329 def test_create_server_invalid_image(self):
330 """Create a server with an unknown image"""
331
332 post_body = json.dumps({
333 'server' : {
334 'name' : 'testserver',
335 'imageRef' : -1,
336 'flavorRef' : self.flavor_ref,
337 }
338 })
339
340 resp, body = self.os.nova.request('POST', '/servers', body=post_body)
341
342 self.assertEqual(400, resp.status)
343
344 fault = json.loads(body)
345 expected_fault = {
346 "badRequest": {
347 "message": "Cannot find requested image",
348 "code": 400,
349 },
350 }
351 # KNOWN-ISSUE - The error message is confusing and should be improved
352 #self.assertEqual(fault, expected_fault)
Soren Hansenfce58c52011-09-09 16:07:13 +0200353 test_create_server_invalid_image.tags = ['nova', 'glance']
Soren Hansenbc1d3a02011-09-08 13:33:17 +0200354
355 def test_create_server_invalid_flavor(self):
356 """Create a server with an unknown flavor"""
357
358 post_body = json.dumps({
359 'server' : {
360 'name' : 'testserver',
361 'imageRef' : self.image_ref,
362 'flavorRef' : -1,
363 }
364 })
365
366 resp, body = self.os.nova.request('POST', '/servers', body=post_body)
367
368 self.assertEqual(400, resp.status)
369
370 fault = json.loads(body)
371 expected_fault = {
372 "badRequest": {
373 "message": "Cannot find requested flavor",
374 "code": 400,
375 },
376 }
377 # KNOWN-ISSUE lp804084
378 #self.assertEqual(fault, expected_fault)
Soren Hansenfce58c52011-09-09 16:07:13 +0200379 test_create_server_invalid_flavor.tags = ['nova', 'glance']