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