Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.rapi.rlib2_unittest.py @ 539d65ba

History | View | Annotate | Download (18.6 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Script for unittesting the RAPI rlib2 module
23

24
"""
25

    
26

    
27
import unittest
28
import tempfile
29

    
30
from ganeti import constants
31
from ganeti import opcodes
32
from ganeti import compat
33
from ganeti import http
34
from ganeti import query
35

    
36
from ganeti.rapi import rlib2
37

    
38
import testutils
39

    
40

    
41
class TestConstants(unittest.TestCase):
42
  def testConsole(self):
43
    # Exporting the console field without authentication might expose
44
    # information
45
    assert "console" in query.INSTANCE_FIELDS
46
    self.assertTrue("console" not in rlib2.I_FIELDS)
47

    
48
  def testFields(self):
49
    checks = {
50
      constants.QR_INSTANCE: rlib2.I_FIELDS,
51
      constants.QR_NODE: rlib2.N_FIELDS,
52
      constants.QR_GROUP: rlib2.G_FIELDS,
53
      }
54

    
55
    for (qr, fields) in checks.items():
56
      self.assertFalse(set(fields) - set(query.ALL_FIELDS[qr].keys()))
57

    
58

    
59
class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
60
  def setUp(self):
61
    testutils.GanetiTestCase.setUp(self)
62

    
63
    self.Parse = rlib2._ParseInstanceCreateRequestVersion1
64

    
65
  def test(self):
66
    disk_variants = [
67
      # No disks
68
      [],
69

    
70
      # Two disks
71
      [{"size": 5, }, {"size": 100, }],
72

    
73
      # Disk with mode
74
      [{"size": 123, "mode": constants.DISK_RDWR, }],
75
      ]
76

    
77
    nic_variants = [
78
      # No NIC
79
      [],
80

    
81
      # Three NICs
82
      [{}, {}, {}],
83

    
84
      # Two NICs
85
      [
86
        { "ip": "192.0.2.6", "mode": constants.NIC_MODE_ROUTED,
87
          "mac": "01:23:45:67:68:9A",
88
        },
89
        { "mode": constants.NIC_MODE_BRIDGED, "link": "br1" },
90
      ],
91
      ]
92

    
93
    beparam_variants = [
94
      None,
95
      {},
96
      { constants.BE_VCPUS: 2, },
97
      { constants.BE_MEMORY: 123, },
98
      { constants.BE_VCPUS: 2,
99
        constants.BE_MEMORY: 1024,
100
        constants.BE_AUTO_BALANCE: True, }
101
      ]
102

    
103
    hvparam_variants = [
104
      None,
105
      { constants.HV_BOOT_ORDER: "anc", },
106
      { constants.HV_KERNEL_PATH: "/boot/fookernel",
107
        constants.HV_ROOT_PATH: "/dev/hda1", },
108
      ]
109

    
110
    for mode in [constants.INSTANCE_CREATE, constants.INSTANCE_IMPORT]:
111
      for nics in nic_variants:
112
        for disk_template in constants.DISK_TEMPLATES:
113
          for disks in disk_variants:
114
            for beparams in beparam_variants:
115
              for hvparams in hvparam_variants:
116
                data = {
117
                  "name": "inst1.example.com",
118
                  "hypervisor": constants.HT_FAKE,
119
                  "disks": disks,
120
                  "nics": nics,
121
                  "mode": mode,
122
                  "disk_template": disk_template,
123
                  "os": "debootstrap",
124
                  }
125

    
126
                if beparams is not None:
127
                  data["beparams"] = beparams
128

    
129
                if hvparams is not None:
130
                  data["hvparams"] = hvparams
131

    
132
                for dry_run in [False, True]:
133
                  op = self.Parse(data, dry_run)
134
                  self.assert_(isinstance(op, opcodes.OpInstanceCreate))
135
                  self.assertEqual(op.mode, mode)
136
                  self.assertEqual(op.disk_template, disk_template)
137
                  self.assertEqual(op.dry_run, dry_run)
138
                  self.assertEqual(len(op.disks), len(disks))
139
                  self.assertEqual(len(op.nics), len(nics))
140

    
141
                  for opdisk, disk in zip(op.disks, disks):
142
                    for key in constants.IDISK_PARAMS:
143
                      self.assertEqual(opdisk.get(key), disk.get(key))
144
                    self.assertFalse("unknown" in opdisk)
145

    
146
                  for opnic, nic in zip(op.nics, nics):
147
                    for key in constants.INIC_PARAMS:
148
                      self.assertEqual(opnic.get(key), nic.get(key))
149
                    self.assertFalse("unknown" in opnic)
150
                    self.assertFalse("foobar" in opnic)
151

    
152
                  if beparams is None:
153
                    self.assertFalse(hasattr(op, "beparams"))
154
                  else:
155
                    self.assertEqualValues(op.beparams, beparams)
156

    
157
                  if hvparams is None:
158
                    self.assertFalse(hasattr(op, "hvparams"))
159
                  else:
160
                    self.assertEqualValues(op.hvparams, hvparams)
161

    
162
  def testLegacyName(self):
163
    name = "inst29128.example.com"
164
    data = {
165
      "name": name,
166
      "disks": [],
167
      "nics": [],
168
      "mode": constants.INSTANCE_CREATE,
169
      "disk_template": constants.DT_PLAIN,
170
      }
171
    op = self.Parse(data, False)
172
    self.assert_(isinstance(op, opcodes.OpInstanceCreate))
173
    self.assertEqual(op.instance_name, name)
174
    self.assertFalse(hasattr(op, "name"))
175

    
176
    # Define both
177
    data = {
178
      "name": name,
179
      "instance_name": "other.example.com",
180
      "disks": [],
181
      "nics": [],
182
      "mode": constants.INSTANCE_CREATE,
183
      "disk_template": constants.DT_PLAIN,
184
      }
185
    self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
186

    
187
  def testLegacyOs(self):
188
    name = "inst4673.example.com"
189
    os = "linux29206"
190
    data = {
191
      "name": name,
192
      "os_type": os,
193
      "disks": [],
194
      "nics": [],
195
      "mode": constants.INSTANCE_CREATE,
196
      "disk_template": constants.DT_PLAIN,
197
      }
198
    op = self.Parse(data, False)
199
    self.assert_(isinstance(op, opcodes.OpInstanceCreate))
200
    self.assertEqual(op.instance_name, name)
201
    self.assertEqual(op.os_type, os)
202
    self.assertFalse(hasattr(op, "os"))
203

    
204
    # Define both
205
    data = {
206
      "instance_name": name,
207
      "os": os,
208
      "os_type": "linux9584",
209
      "disks": [],
210
      "nics": [],
211
      "mode": constants.INSTANCE_CREATE,
212
      "disk_template": constants.DT_PLAIN,
213
      }
214
    self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
215

    
216
  def testErrors(self):
217
    # Test all required fields
218
    reqfields = {
219
      "name": "inst1.example.com",
220
      "disks": [],
221
      "nics": [],
222
      "mode": constants.INSTANCE_CREATE,
223
      "disk_template": constants.DT_PLAIN,
224
      }
225

    
226
    for name in reqfields.keys():
227
      self.assertRaises(http.HttpBadRequest, self.Parse,
228
                        dict(i for i in reqfields.iteritems() if i[0] != name),
229
                        False)
230

    
231
    # Invalid disks and nics
232
    for field in ["disks", "nics"]:
233
      invalid_values = [None, 1, "", {}, [1, 2, 3], ["hda1", "hda2"],
234
                        [{"_unknown_": 999, }]]
235

    
236
      for invvalue in invalid_values:
237
        data = reqfields.copy()
238
        data[field] = invvalue
239
        self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
240

    
241

    
242
class TestParseExportInstanceRequest(testutils.GanetiTestCase):
243
  def setUp(self):
244
    testutils.GanetiTestCase.setUp(self)
245

    
246
    self.Parse = rlib2._ParseExportInstanceRequest
247

    
248
  def test(self):
249
    name = "instmoo"
250
    data = {
251
      "mode": constants.EXPORT_MODE_REMOTE,
252
      "destination": [(1, 2, 3), (99, 99, 99)],
253
      "shutdown": True,
254
      "remove_instance": True,
255
      "x509_key_name": ["name", "hash"],
256
      "destination_x509_ca": "---cert---"
257
      }
258
    op = self.Parse(name, data)
259
    self.assert_(isinstance(op, opcodes.OpBackupExport))
260
    self.assertEqual(op.instance_name, name)
261
    self.assertEqual(op.mode, constants.EXPORT_MODE_REMOTE)
262
    self.assertEqual(op.shutdown, True)
263
    self.assertEqual(op.remove_instance, True)
264
    self.assertEqualValues(op.x509_key_name, ("name", "hash"))
265
    self.assertEqual(op.destination_x509_ca, "---cert---")
266

    
267
  def testDefaults(self):
268
    name = "inst1"
269
    data = {
270
      "destination": "node2",
271
      "shutdown": False,
272
      }
273
    op = self.Parse(name, data)
274
    self.assert_(isinstance(op, opcodes.OpBackupExport))
275
    self.assertEqual(op.instance_name, name)
276
    self.assertEqual(op.target_node, "node2")
277
    self.assertFalse(hasattr(op, "mode"))
278
    self.assertFalse(hasattr(op, "remove_instance"))
279
    self.assertFalse(hasattr(op, "destination"))
280

    
281
  def testErrors(self):
282
    self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
283
                      { "remove_instance": "True", })
284
    self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
285
                      { "remove_instance": "False", })
286

    
287

    
288
class TestParseMigrateInstanceRequest(testutils.GanetiTestCase):
289
  def setUp(self):
290
    testutils.GanetiTestCase.setUp(self)
291

    
292
    self.Parse = rlib2._ParseMigrateInstanceRequest
293

    
294
  def test(self):
295
    name = "instYooho6ek"
296

    
297
    for cleanup in [False, True]:
298
      for mode in constants.HT_MIGRATION_MODES:
299
        data = {
300
          "cleanup": cleanup,
301
          "mode": mode,
302
          }
303
        op = self.Parse(name, data)
304
        self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
305
        self.assertEqual(op.instance_name, name)
306
        self.assertEqual(op.mode, mode)
307
        self.assertEqual(op.cleanup, cleanup)
308

    
309
  def testDefaults(self):
310
    name = "instnohZeex0"
311

    
312
    op = self.Parse(name, {})
313
    self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
314
    self.assertEqual(op.instance_name, name)
315
    self.assertFalse(hasattr(op, "mode"))
316
    self.assertFalse(hasattr(op, "cleanup"))
317

    
318

    
319
class TestParseRenameInstanceRequest(testutils.GanetiTestCase):
320
  def setUp(self):
321
    testutils.GanetiTestCase.setUp(self)
322

    
323
    self.Parse = rlib2._ParseRenameInstanceRequest
324

    
325
  def test(self):
326
    name = "instij0eeph7"
327

    
328
    for new_name in ["ua0aiyoo", "fai3ongi"]:
329
      for ip_check in [False, True]:
330
        for name_check in [False, True]:
331
          data = {
332
            "new_name": new_name,
333
            "ip_check": ip_check,
334
            "name_check": name_check,
335
            }
336

    
337
          op = self.Parse(name, data)
338
          self.assert_(isinstance(op, opcodes.OpInstanceRename))
339
          self.assertEqual(op.instance_name, name)
340
          self.assertEqual(op.new_name, new_name)
341
          self.assertEqual(op.ip_check, ip_check)
342
          self.assertEqual(op.name_check, name_check)
343

    
344
  def testDefaults(self):
345
    name = "instahchie3t"
346

    
347
    for new_name in ["thag9mek", "quees7oh"]:
348
      data = {
349
        "new_name": new_name,
350
        }
351

    
352
      op = self.Parse(name, data)
353
      self.assert_(isinstance(op, opcodes.OpInstanceRename))
354
      self.assertEqual(op.instance_name, name)
355
      self.assertEqual(op.new_name, new_name)
356
      self.assertFalse(hasattr(op, "ip_check"))
357
      self.assertFalse(hasattr(op, "name_check"))
358

    
359

    
360
class TestParseModifyInstanceRequest(testutils.GanetiTestCase):
361
  def setUp(self):
362
    testutils.GanetiTestCase.setUp(self)
363

    
364
    self.Parse = rlib2._ParseModifyInstanceRequest
365

    
366
  def test(self):
367
    name = "instush8gah"
368

    
369
    test_disks = [
370
      [],
371
      [(1, { constants.IDISK_MODE: constants.DISK_RDWR, })],
372
      ]
373

    
374
    for osparams in [{}, { "some": "value", "other": "Hello World", }]:
375
      for hvparams in [{}, { constants.HV_KERNEL_PATH: "/some/kernel", }]:
376
        for beparams in [{}, { constants.BE_MEMORY: 128, }]:
377
          for force in [False, True]:
378
            for nics in [[], [(0, { constants.INIC_IP: "192.0.2.1", })]]:
379
              for disks in test_disks:
380
                for disk_template in constants.DISK_TEMPLATES:
381
                  data = {
382
                    "osparams": osparams,
383
                    "hvparams": hvparams,
384
                    "beparams": beparams,
385
                    "nics": nics,
386
                    "disks": disks,
387
                    "force": force,
388
                    "disk_template": disk_template,
389
                    }
390

    
391
                  op = self.Parse(name, data)
392
                  self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
393
                  self.assertEqual(op.instance_name, name)
394
                  self.assertEqual(op.hvparams, hvparams)
395
                  self.assertEqual(op.beparams, beparams)
396
                  self.assertEqual(op.osparams, osparams)
397
                  self.assertEqual(op.force, force)
398
                  self.assertEqual(op.nics, nics)
399
                  self.assertEqual(op.disks, disks)
400
                  self.assertEqual(op.disk_template, disk_template)
401
                  self.assertFalse(hasattr(op, "remote_node"))
402
                  self.assertFalse(hasattr(op, "os_name"))
403
                  self.assertFalse(hasattr(op, "force_variant"))
404

    
405
  def testDefaults(self):
406
    name = "instir8aish31"
407

    
408
    op = self.Parse(name, {})
409
    self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
410
    self.assertEqual(op.instance_name, name)
411
    for i in ["hvparams", "beparams", "osparams", "force", "nics", "disks",
412
              "disk_template", "remote_node", "os_name", "force_variant"]:
413
      self.assertFalse(hasattr(op, i))
414

    
415

    
416
class TestParseInstanceReinstallRequest(testutils.GanetiTestCase):
417
  def setUp(self):
418
    testutils.GanetiTestCase.setUp(self)
419

    
420
    self.Parse = rlib2._ParseInstanceReinstallRequest
421

    
422
  def _Check(self, ops, name):
423
    expcls = [
424
      opcodes.OpInstanceShutdown,
425
      opcodes.OpInstanceReinstall,
426
      opcodes.OpInstanceStartup,
427
      ]
428

    
429
    self.assert_(compat.all(isinstance(op, exp)
430
                            for op, exp in zip(ops, expcls)))
431
    self.assert_(compat.all(op.instance_name == name for op in ops))
432

    
433
  def test(self):
434
    name = "shoo0tihohma"
435

    
436
    ops = self.Parse(name, {"os": "sys1", "start": True,})
437
    self.assertEqual(len(ops), 3)
438
    self._Check(ops, name)
439
    self.assertEqual(ops[1].os_type, "sys1")
440
    self.assertFalse(ops[1].osparams)
441

    
442
    ops = self.Parse(name, {"os": "sys2", "start": False,})
443
    self.assertEqual(len(ops), 2)
444
    self._Check(ops, name)
445
    self.assertEqual(ops[1].os_type, "sys2")
446

    
447
    osparams = {
448
      "reformat": "1",
449
      }
450
    ops = self.Parse(name, {"os": "sys4035", "start": True,
451
                            "osparams": osparams,})
452
    self.assertEqual(len(ops), 3)
453
    self._Check(ops, name)
454
    self.assertEqual(ops[1].os_type, "sys4035")
455
    self.assertEqual(ops[1].osparams, osparams)
456

    
457
  def testDefaults(self):
458
    name = "noolee0g"
459

    
460
    ops = self.Parse(name, {"os": "linux1"})
461
    self.assertEqual(len(ops), 3)
462
    self._Check(ops, name)
463
    self.assertEqual(ops[1].os_type, "linux1")
464
    self.assertFalse(ops[1].osparams)
465

    
466

    
467
class TestParseRenameGroupRequest(testutils.GanetiTestCase):
468
  def setUp(self):
469
    testutils.GanetiTestCase.setUp(self)
470

    
471
    self.Parse = rlib2._ParseRenameGroupRequest
472

    
473
  def test(self):
474
    name = "instij0eeph7"
475
    data = {
476
      "new_name": "ua0aiyoo",
477
      }
478

    
479
    op = self.Parse(name, data, False)
480

    
481
    self.assert_(isinstance(op, opcodes.OpGroupRename))
482
    self.assertEqual(op.group_name, name)
483
    self.assertEqual(op.new_name, "ua0aiyoo")
484
    self.assertFalse(op.dry_run)
485

    
486
  def testDryRun(self):
487
    name = "instij0eeph7"
488
    data = {
489
      "new_name": "ua0aiyoo",
490
      }
491

    
492
    op = self.Parse(name, data, True)
493

    
494
    self.assert_(isinstance(op, opcodes.OpGroupRename))
495
    self.assertEqual(op.group_name, name)
496
    self.assertEqual(op.new_name, "ua0aiyoo")
497
    self.assert_(op.dry_run)
498

    
499

    
500
class TestParseInstanceReplaceDisksRequest(unittest.TestCase):
501
  def setUp(self):
502
    self.Parse = rlib2._ParseInstanceReplaceDisksRequest
503

    
504
  def test(self):
505
    name = "inst22568"
506

    
507
    for disks in [range(1, 4), "1,2,3", "1, 2, 3"]:
508
      data = {
509
        "mode": constants.REPLACE_DISK_SEC,
510
        "disks": disks,
511
        "iallocator": "myalloc",
512
        }
513

    
514
      op = self.Parse(name, data)
515
      self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
516
      self.assertEqual(op.mode, constants.REPLACE_DISK_SEC)
517
      self.assertEqual(op.disks, [1, 2, 3])
518
      self.assertEqual(op.iallocator, "myalloc")
519

    
520
  def testDefaults(self):
521
    name = "inst11413"
522
    data = {
523
      "mode": constants.REPLACE_DISK_AUTO,
524
      }
525

    
526
    op = self.Parse(name, data)
527
    self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
528
    self.assertEqual(op.mode, constants.REPLACE_DISK_AUTO)
529
    self.assertFalse(hasattr(op, "iallocator"))
530
    self.assertFalse(hasattr(op, "disks"))
531

    
532
  def testNoDisks(self):
533
    self.assertRaises(http.HttpBadRequest, self.Parse, "inst20661", {})
534

    
535
    for disks in [None, "", {}]:
536
      self.assertRaises(http.HttpBadRequest, self.Parse, "inst20661", {
537
        "disks": disks,
538
        })
539

    
540
  def testWrong(self):
541
    self.assertRaises(http.HttpBadRequest, self.Parse, "inst",
542
                      { "mode": constants.REPLACE_DISK_AUTO,
543
                        "disks": "hello world",
544
                      })
545

    
546

    
547
class TestParseModifyGroupRequest(unittest.TestCase):
548
  def setUp(self):
549
    self.Parse = rlib2._ParseModifyGroupRequest
550

    
551
  def test(self):
552
    name = "group6002"
553

    
554
    for policy in constants.VALID_ALLOC_POLICIES:
555
      data = {
556
        "alloc_policy": policy,
557
        }
558

    
559
      op = self.Parse(name, data)
560
      self.assert_(isinstance(op, opcodes.OpGroupSetParams))
561
      self.assertEqual(op.group_name, name)
562
      self.assertEqual(op.alloc_policy, policy)
563

    
564
  def testUnknownPolicy(self):
565
    data = {
566
      "alloc_policy": "_unknown_policy_",
567
      }
568

    
569
    self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
570

    
571
  def testDefaults(self):
572
    name = "group6679"
573
    data = {}
574

    
575
    op = self.Parse(name, data)
576
    self.assert_(isinstance(op, opcodes.OpGroupSetParams))
577
    self.assertEqual(op.group_name, name)
578
    self.assertFalse(hasattr(op, "alloc_policy"))
579

    
580

    
581
class TestParseCreateGroupRequest(unittest.TestCase):
582
  def setUp(self):
583
    self.Parse = rlib2._ParseCreateGroupRequest
584

    
585
  def test(self):
586
    name = "group3618"
587

    
588
    for policy in constants.VALID_ALLOC_POLICIES:
589
      data = {
590
        "group_name": name,
591
        "alloc_policy": policy,
592
        }
593

    
594
      op = self.Parse(data, False)
595
      self.assert_(isinstance(op, opcodes.OpGroupAdd))
596
      self.assertEqual(op.group_name, name)
597
      self.assertEqual(op.alloc_policy, policy)
598
      self.assertFalse(op.dry_run)
599

    
600
  def testUnknownPolicy(self):
601
    data = {
602
      "alloc_policy": "_unknown_policy_",
603
      }
604

    
605
    self.assertRaises(http.HttpBadRequest, self.Parse, "name", data)
606

    
607
  def testDefaults(self):
608
    name = "group15395"
609
    data = {
610
      "group_name": name,
611
      }
612

    
613
    op = self.Parse(data, True)
614
    self.assert_(isinstance(op, opcodes.OpGroupAdd))
615
    self.assertEqual(op.group_name, name)
616
    self.assertFalse(hasattr(op, "alloc_policy"))
617
    self.assertTrue(op.dry_run)
618

    
619
  def testLegacyName(self):
620
    name = "group29852"
621
    data = {
622
      "name": name,
623
      }
624

    
625
    op = self.Parse(data, True)
626
    self.assert_(isinstance(op, opcodes.OpGroupAdd))
627
    self.assertEqual(op.group_name, name)
628

    
629

    
630
if __name__ == '__main__':
631
  testutils.GanetiTestProgram()