Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / test / cyclades.py @ 8f5d38df

History | View | Annotate | Download (20.6 kB)

1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33
from mock import patch, Mock
34
from unittest import TestCase
35
from json import loads
36

    
37
from kamaki.clients import Client, ClientError
38
from kamaki.clients.cyclades_rest_api import CycladesClientApi
39

    
40
img_ref = "1m4g3-r3f3r3nc3"
41
vm_name = "my new VM"
42
fid = 42
43
vm_send = dict(server=dict(
44
    flavorRef=fid,
45
    name=vm_name,
46
    imageRef=img_ref,
47
    metadata=dict(os="debian", users="root")))
48
vm_recv = dict(server=dict(
49
    status="BUILD",
50
    updated="2013-03-01T10:04:00.637152+00:00",
51
    hostId="",
52
    name=vm_name,
53
    imageRef=img_ref,
54
    created="2013-03-01T10:04:00.087324+00:00",
55
    flavorRef=fid,
56
    adminPass="n0n3sh@11p@55",
57
    suspended=False,
58
    progress=0,
59
    id=31173,
60
    metadata=dict(values=dict(os="debian", users="root"))))
61
img_recv = dict(image=dict(
62
    status="ACTIVE",
63
    updated="2013-02-26T11:10:14+00:00",
64
    name="Debian Base",
65
    created="2013-02-26T11:03:29+00:00",
66
    progress=100,
67
    id=img_ref,
68
    metadata=dict(values=dict(
69
        partition_table="msdos",
70
        kernel="2.6.32",
71
        osfamily="linux",
72
        users="root",
73
        gui="No GUI",
74
        sortorder="1",
75
        os="debian",
76
        root_partition="1",
77
        description="Debian 6.0.7 (Squeeze) Base System"))))
78
vm_list = dict(servers=dict(values=[
79
    dict(name='n1', id=1),
80
    dict(name='n2', id=2)]))
81
flavor_list = dict(flavors=dict(values=[
82
        dict(id=1, name="C1R1024D20"),
83
        dict(id=2, name="C1R1024D40"),
84
        dict(id=3, name="C1R1028D20")
85
    ]))
86

    
87

    
88
class Cyclades(TestCase):
89

    
90
    def assert_dicts_are_equal(self, d1, d2):
91
        for k, v in d1.items():
92
            self.assertTrue(k in d2)
93
            if isinstance(v, dict):
94
                self.assert_dicts_are_equal(v, d2[k])
95
            else:
96
                self.assertEqual(unicode(v), unicode(d2[k]))
97

    
98
    class FR(object):
99
        """FR stands for Fake Response"""
100
        json = vm_recv
101
        headers = {}
102
        content = json
103
        status = None
104
        status_code = 200
105

    
106
        def release(self):
107
            pass
108

    
109
    """Set up a Cyclades thorough test"""
110
    def setUp(self):
111
        self.url = 'http://cyclades.example.com'
112
        self.token = 'cyc14d3s70k3n'
113
        from kamaki.clients.cyclades import CycladesClient
114
        self.client = CycladesClient(self.url, self.token)
115
        from kamaki.clients.connection.kamakicon import KamakiHTTPConnection
116
        self.C = KamakiHTTPConnection
117

    
118
    def tearDown(self):
119
        self.FR.status_code = 200
120
        self.FR.json = vm_recv
121

    
122
    def test_create_server(self):
123
        self.client.get_image_details = Mock(return_value=img_recv['image'])
124
        with patch.object(Client, 'request', side_effect=ClientError(
125
                'REQUEST ENTITY TOO LARGE',
126
                status=403)):
127
            self.assertRaises(
128
                ClientError,
129
                self.client.create_server,
130
                vm_name, fid, img_ref)
131

    
132
        with patch.object(
133
                self.C,
134
                'perform_request',
135
                return_value=self.FR()) as perform_req:
136
            self.assertRaises(
137
                ClientError,
138
                self.client.create_server,
139
                vm_name, fid, img_ref)
140
            self.FR.status_code = 202
141
            r = self.client.create_server(vm_name, fid, img_ref)
142
            self.assertEqual(self.client.http_client.url, self.url)
143
            self.assertEqual(self.client.http_client.path, '/servers')
144
            (method, data, a_headers, a_params) = perform_req.call_args[0]
145
            self.assert_dicts_are_equal(loads(data), vm_send)
146
            self.assert_dicts_are_equal(r, vm_recv['server'])
147
            prsn = 'Personality string (does not work with real servers)'
148
            self.client.create_server(vm_name, fid, img_ref, prsn)
149
            (method, data, a_headers, a_params) = perform_req.call_args[0]
150
            data = loads(data)
151
            self.assertTrue('personality' in data['server'])
152
            self.assertEqual(prsn, data['server']['personality'])
153

    
154
    def test_list_servers(self):
155
        self.FR.json = vm_list
156
        with patch.object(
157
                self.C,
158
                'perform_request',
159
                return_value=self.FR()) as perform_req:
160
            r = self.client.list_servers()
161
            self.assertEqual(self.client.http_client.url, self.url)
162
            self.assertEqual(self.client.http_client.path, '/servers')
163
            (method, data, a_headers, a_params) = perform_req.call_args[0]
164
            self.assert_dicts_are_equal(dict(values=r), vm_list['servers'])
165
            r = self.client.list_servers(detail=True)
166
            self.assertEqual(self.client.http_client.url, self.url)
167
            self.assertEqual(self.client.http_client.path, '/servers/detail')
168
        with patch.object(
169
                CycladesClientApi,
170
                'servers_get',
171
                return_value=self.FR()) as servers_get:
172
            self.client.list_servers(changes_since=True)
173
            self.assertTrue(servers_get.call_args[1]['changes_since'])
174

    
175
    def test_get_server_details(self):
176
        vm_id = vm_recv['server']['id']
177
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
178
            r = self.client.get_server_details(vm_id)
179
            self.assertEqual(self.client.http_client.url, self.url)
180
            self.assertEqual(
181
                self.client.http_client.path,
182
                '/servers/%s' % vm_id)
183
            self.assert_dicts_are_equal(r, vm_recv['server'])
184

    
185
    def test_update_server_name(self):
186
        vm_id = vm_recv['server']['id']
187
        new_name = vm_name + '_new'
188
        self.FR.status_code = 204
189
        with patch.object(
190
                self.C,
191
                'perform_request',
192
                return_value=self.FR()) as perform_req:
193
            self.client.update_server_name(vm_id, new_name)
194
            self.assertEqual(self.client.http_client.url, self.url)
195
            self.assertEqual(
196
                self.client.http_client.path,
197
                '/servers/%s' % vm_id)
198
            (method, data, a_headers, a_params) = perform_req.call_args[0]
199
            self.assert_dicts_are_equal(
200
                dict(server=dict(name=new_name)),
201
                loads(data))
202

    
203
    def test_reboot_server(self):
204
        vm_id = vm_recv['server']['id']
205
        self.FR.status_code = 202
206
        with patch.object(
207
                self.C,
208
                'perform_request',
209
                return_value=self.FR()) as perform_req:
210
            self.client.reboot_server(vm_id)
211
            self.assertEqual(self.client.http_client.url, self.url)
212
            self.assertEqual(
213
                self.client.http_client.path,
214
                '/servers/%s/action' % vm_id)
215
            (method, data, a_headers, a_params) = perform_req.call_args[0]
216
            self.assert_dicts_are_equal(
217
                dict(reboot=dict(type='SOFT')),
218
                loads(data))
219

    
220
    def test_create_server_metadata(self):
221
        vm_id = vm_recv['server']['id']
222
        metadata = dict(m1='v1', m2='v2', m3='v3')
223
        self.FR.json = dict(meta=vm_recv['server'])
224
        with patch.object(
225
                self.C,
226
                'perform_request',
227
                return_value=self.FR()) as perform_req:
228
            self.assertRaises(
229
                ClientError,
230
                self.client.create_server_metadata,
231
                vm_id, 'key', 'value')
232
            self.FR.status_code = 201
233
            for k, v in metadata.items():
234
                r = self.client.create_server_metadata(vm_id, k, v)
235
                self.assertEqual(self.client.http_client.url, self.url)
236
                self.assertEqual(
237
                    self.client.http_client.path,
238
                    '/servers/%s/meta/%s' % (vm_id, k))
239
                (method, data, a_headers, a_params) = perform_req.call_args[0]
240
                self.assertEqual(dict(meta={k: v}), loads(data))
241
                self.assert_dicts_are_equal(r, vm_recv['server'])
242

    
243
    def test_get_server_metadata(self):
244
        vm_id = vm_recv['server']['id']
245
        metadata = dict(m1='v1', m2='v2', m3='v3')
246
        with patch.object(self.C, 'perform_request', return_value=self.FR()):
247
            self.FR.json = dict(metadata=dict(values=metadata))
248
            r = self.client.get_server_metadata(vm_id)
249
            self.assertEqual(self.client.http_client.url, self.url)
250
            self.assertEqual(
251
                self.client.http_client.path,
252
                '/servers/%s/meta' % vm_id)
253
            self.assert_dicts_are_equal(r, metadata)
254

    
255
            for k, v in metadata.items():
256
                self.FR.json = dict(meta={k: v})
257
                r = self.client.get_server_metadata(vm_id, k)
258
                self.assertEqual(self.client.http_client.url, self.url)
259
                self.assertEqual(
260
                    self.client.http_client.path,
261
                    '/servers/%s/meta/%s' % (vm_id, k))
262
                self.assert_dicts_are_equal(r, {k: v})
263

    
264
    def test_update_server_metadata(self):
265
        vm_id = vm_recv['server']['id']
266
        metadata = dict(m1='v1', m2='v2', m3='v3')
267
        self.FR.json = dict(metadata=metadata)
268
        with patch.object(
269
                CycladesClientApi,
270
                'servers_post',
271
                return_value=self.FR()) as servers_post:
272
            r = self.client.update_server_metadata(vm_id, **metadata)
273
            self.assert_dicts_are_equal(r, metadata)
274
            (called_id, cmd) = servers_post.call_args[0]
275
            self.assertEqual(called_id, vm_id)
276
            self.assertEqual(cmd, 'meta')
277
            data = servers_post.call_args[1]['json_data']
278
            self.assert_dicts_are_equal(data, dict(metadata=metadata))
279

    
280
    def test_delete_server_metadata(self):
281
        vm_id = vm_recv['server']['id']
282
        key = 'metakey'
283
        with patch.object(
284
                CycladesClientApi,
285
                'servers_delete',
286
                return_value=self.FR()) as servers_delete:
287
            self.client.delete_server_metadata(vm_id, key)
288
            self.assertEqual(
289
                (vm_id, 'meta/' + key),
290
                servers_delete.call_args[0])
291

    
292
    def test_list_flavors(self):
293
        self.FR.json = vm_list
294
        self.FR.json = flavor_list
295
        with patch.object(
296
                self.C,
297
                'perform_request',
298
                return_value=self.FR()) as perform_req:
299
            r = self.client.list_flavors()
300
            self.assertEqual(self.client.http_client.url, self.url)
301
            self.assertEqual(self.client.http_client.path, '/flavors')
302
            (method, data, a_headers, a_params) = perform_req.call_args[0]
303
            self.assert_dicts_are_equal(dict(values=r), flavor_list['flavors'])
304
            r = self.client.list_flavors(detail=True)
305
            self.assertEqual(self.client.http_client.url, self.url)
306
            self.assertEqual(self.client.http_client.path, '/flavors/detail')
307

    
308
    """
309
    def test_get_flavor_details(self):
310
        r = self.client.get_flavor_details(self.flavorid)
311
        self.assert_dicts_are_equal(self._flavor_details, r)
312

313
    def test_list_images(self):
314
        r = self.client.list_images()
315
        self.assertTrue(len(r) > 1)
316
        r = self.client.list_images(detail=True)
317
        for detailed_img in r:
318
            if detailed_img['id'] == self.img:
319
                break
320
        self.assert_dicts_are_equal(detailed_img, self.img_details)
321

322
    def test_get_image_details(self):
323
        r = self.client.get_image_details(self.img)
324
        self.assert_dicts_are_equal(r, self.img_details)
325

326
    def test_get_image_metadata(self):
327
        r = self.client.get_image_metadata(self.img)
328
        self.assert_dicts_are_equal(
329
            self.img_details['metadata']['values'], r)
330
        for key, val in self.img_details['metadata']['values'].items():
331
            r = self.client.get_image_metadata(self.img, key)
332
            self.assertEqual(r[key], val)
333

334
    def test_shutdown_server(self):
335
        self.client.shutdown_server(self.server1['id'])
336
        self._wait_for_status(self.server1['id'], 'ACTIVE')
337
        r = self.client.get_server_details(self.server1['id'])
338
        self.assertEqual(r['status'], 'STOPPED')
339

340
    def test_start_server(self):
341
        self.client.start_server(self.server1['id'])
342
        self._wait_for_status(self.server1['id'], 'STOPPED')
343
        r = self.client.get_server_details(self.server1['id'])
344
        self.assertEqual(r['status'], 'ACTIVE')
345

346
    def test_get_server_console(self):
347
        r = self.client.get_server_console(self.server2['id'])
348
        self.assertTrue('host' in r)
349
        self.assertTrue('password' in r)
350
        self.assertTrue('port' in r)
351
        self.assertTrue('type' in r)
352

353
    def test_get_firewall_profile(self):
354
        self._wait_for_status(self.server1['id'], 'BUILD')
355
        fprofile = self.client.get_firewall_profile(self.server1['id'])
356
        self.assertTrue(fprofile in self.PROFILES)
357

358
    def test_set_firewall_profile(self):
359
        self._wait_for_status(self.server1['id'], 'BUILD')
360
        PROFILES = ['DISABLED', 'ENABLED', 'DISABLED', 'PROTECTED']
361
        fprofile = self.client.get_firewall_profile(self.server1['id'])
362
        print('')
363
        count_success = 0
364
        for counter, fprofile in enumerate(PROFILES):
365
            npos = counter + 1
366
            try:
367
                nprofile = PROFILES[npos]
368
            except IndexError:
369
                nprofile = PROFILES[0]
370
            print('\tprofile swap %s: %s -> %s' % (npos, fprofile, nprofile))
371
            self.client.set_firewall_profile(self.server1['id'], nprofile)
372
            time.sleep(0.5)
373
            self.client.reboot_server(self.server1['id'], hard=True)
374
            time.sleep(1)
375
            self._wait_for_status(self.server1['id'], 'REBOOT')
376
            time.sleep(0.5)
377
            changed = self.client.get_firewall_profile(self.server1['id'])
378
            try:
379
                self.assertEqual(changed, nprofile)
380
            except AssertionError as err:
381
                if count_success:
382
                    print('\tFAIL in swap #%s' % npos)
383
                    break
384
                else:
385
                    raise err
386
            count_success += 1
387

388
    def test_get_server_stats(self):
389
        r = self.client.get_server_stats(self.server1['id'])
390
        it = ('cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries', 'refresh')
391
        for term in it:
392
            self.assertTrue(term in r)
393

394
    def test_create_network(self):
395
        print('\twith no params')
396
        self.network1 = self._create_network(self.netname1)
397
        self._wait_for_network(self.network1['id'], 'ACTIVE')
398
        n1id = self.network1['id']
399
        self.network1 = self.client.get_network_details(n1id)
400
        nets = self.client.list_networks(self.network1['id'])
401
        chosen = [net for net in nets if net['id'] == n1id][0]
402
        chosen.pop('updated')
403
        net1 = dict(self.network1)
404
        net1.pop('updated')
405
        self.assert_dicts_are_equal(chosen, net1)
406
        for param, val in dict(
407
                cidr='192.168.0.0/24',
408
                gateway='192.168.0.1',
409
                type='MAC_FILTERED',
410
                dhcp=True).items():
411
            print('\tdelete %s to avoid max net limit' % n1id)
412
            self._delete_network(n1id)
413
            kwargs = {param: val}
414
            print('\twith %s=%s' % (param, val))
415
            self.network1 = self._create_network(self.netname1, **kwargs)
416
            n1id = self.network1['id']
417
            self._wait_for_network(n1id, 'ACTIVE')
418
            self.network1 = self.client.get_network_details(n1id)
419
            self.assertEqual(self.network1[param], val)
420

421
    def test_connect_server(self):
422
        self.client.connect_server(self.server1['id'], self.network1['id'])
423
        self.assertTrue(self._wait_for_nic(
424
            self.network1['id'],
425
            self.server1['id']))
426

427
    def test_disconnect_server(self):
428
        self.client.disconnect_server(self.server1['id'], self.network1['id'])
429
        self.assertTrue(self._wait_for_nic(
430
            self.network1['id'],
431
            self.server1['id'],
432
            in_creation=False))
433

434
    def _test_0260_wait_for_second_network(self):
435
        self.server1 = self._create_server(
436
            self.servname1,
437
            self.flavorid,
438
            self.img)
439
        self.network2 = self._create_network(self.netname2)
440
        self._wait_for_status(self.server1['id'], 'BUILD')
441
        self._wait_for_network(self.network2['id'], 'ACTIVE')
442
        self._test_0280_list_server_nics()
443

444
    def _test_0280_list_server_nics(self):
445
        r = self.client.list_server_nics(self.server1['id'])
446
        len0 = len(r)
447
        self.client.connect_server(self.server1['id'], self.network2['id'])
448
        self.assertTrue(self._wait_for_nic(
449
            self.network2['id'],
450
            self.server1['id']))
451
        r = self.client.list_server_nics(self.server1['id'])
452
        self.assertTrue(len(r) > len0)
453

454
    def test_list_networks(self):
455
        r = self.client.list_networks()
456
        self.assertTrue(len(r) > 1)
457
        ids = [net['id'] for net in r]
458
        names = [net['name'] for net in r]
459
        self.assertTrue('1' in ids)
460
        #self.assertTrue('public' in names)
461
        self.assertTrue(self.network1['id'] in ids)
462
        self.assertTrue(self.network1['name'] in names)
463

464
        r = self.client.list_networks(detail=True)
465
        ids = [net['id'] for net in r]
466
        names = [net['name'] for net in r]
467
        for net in r:
468
            self.assertTrue(net['id'] in ids)
469
            self.assertTrue(net['name'] in names)
470
            for term in ('status', 'updated', 'created'):
471
                self.assertTrue(term in net.keys())
472

473
    def test_get_network_details(self):
474
        r = self.client.get_network_details(self.network1['id'])
475
        net1 = dict(self.network1)
476
        net1.pop('status')
477
        net1.pop('updated', None)
478
        net1.pop('attachments')
479
        r.pop('status')
480
        r.pop('updated', None)
481
        r.pop('attachments')
482
        self.assert_dicts_are_equal(net1, r)
483

484
    def test_update_network_name(self):
485
        updated_name = self.netname2 + '_upd'
486
        self.client.update_network_name(self.network2['id'], updated_name)
487

488
        def netwait(wait):
489
            r = self.client.get_network_details(self.network2['id'])
490
            if r['name'] == updated_name:
491
                return
492
            time.sleep(wait)
493
        self.do_with_progress_bar(
494
            netwait,
495
            'Network %s name is changing:' % self.network2['id'],
496
            self._waits[:5])
497

498
        r = self.client.get_network_details(self.network2['id'])
499
        self.assertEqual(r['name'], updated_name)
500

501
    def test_delete_image(self):
502
        images = self.client.list_images()
503
        self.client.delete_image(images[2]['id'])
504
        try:
505
            r = self.client.get_image_details(images[2]['id'], success=(400))
506
        except ClientError as err:
507
            self.assertEqual(err.status, 404)
508

509
    def test_create_image_metadata(self):
510
        r = self.client.create_image_metadata(self.img, 'mykey', 'myval')
511
        self.assertEqual(r['mykey'], 'myval')
512

513
    def test_update_image_metadata(self):
514
        r = self.client.create_image_metadata(self.img, 'mykey0', 'myval')
515
        r = self.client.update_image_metadata(self.img, 'mykey0', 'myval0')
516
        self.assertEqual(r['mykey0'], 'myval0')
517

518
    def test_delete_image_metadata(self):
519
        self.client.create_image_metadata(self.img, 'mykey1', 'myval1')
520
        self.client.delete_image_metadata(self.img, 'mykey1')
521
        r = self.client.get_image_metadata(self.img)
522
        self.assertNotEqual('mykey1' in r)
523
    """