395a9195c914b065bc1aa35f0d9463bbed20e32a
[ganeti-local] / test / ganeti.rapi.rlib2_unittest.py
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
35 from ganeti.rapi import rlib2
36
37 import testutils
38
39
40 class TestParseInstanceCreateRequestVersion1(testutils.GanetiTestCase):
41   def setUp(self):
42     testutils.GanetiTestCase.setUp(self)
43
44     self.Parse = rlib2._ParseInstanceCreateRequestVersion1
45
46   def test(self):
47     disk_variants = [
48       # No disks
49       [],
50
51       # Two disks
52       [{"size": 5, }, {"size": 100, }],
53
54       # Disk with mode
55       [{"size": 123, "mode": constants.DISK_RDWR, }],
56
57       # With unknown setting
58       [{"size": 123, "unknown": 999 }],
59       ]
60
61     nic_variants = [
62       # No NIC
63       [],
64
65       # Three NICs
66       [{}, {}, {}],
67
68       # Two NICs
69       [
70         { "ip": "192.0.2.6", "mode": constants.NIC_MODE_ROUTED,
71           "mac": "01:23:45:67:68:9A",
72         },
73         { "mode": constants.NIC_MODE_BRIDGED, "link": "n0", "bridge": "br1", },
74       ],
75
76       # Unknown settings
77       [{ "unknown": 999, }, { "foobar": "Hello World", }],
78       ]
79
80     beparam_variants = [
81       None,
82       {},
83       { constants.BE_VCPUS: 2, },
84       { constants.BE_MEMORY: 123, },
85       { constants.BE_VCPUS: 2,
86         constants.BE_MEMORY: 1024,
87         constants.BE_AUTO_BALANCE: True, }
88       ]
89
90     hvparam_variants = [
91       None,
92       { constants.HV_BOOT_ORDER: "anc", },
93       { constants.HV_KERNEL_PATH: "/boot/fookernel",
94         constants.HV_ROOT_PATH: "/dev/hda1", },
95       ]
96
97     for mode in [constants.INSTANCE_CREATE, constants.INSTANCE_IMPORT]:
98       for nics in nic_variants:
99         for disk_template in constants.DISK_TEMPLATES:
100           for disks in disk_variants:
101             for beparams in beparam_variants:
102               for hvparams in hvparam_variants:
103                 data = {
104                   "name": "inst1.example.com",
105                   "hypervisor": constants.HT_FAKE,
106                   "disks": disks,
107                   "nics": nics,
108                   "mode": mode,
109                   "disk_template": disk_template,
110                   "os": "debootstrap",
111                   }
112
113                 if beparams is not None:
114                   data["beparams"] = beparams
115
116                 if hvparams is not None:
117                   data["hvparams"] = hvparams
118
119                 for dry_run in [False, True]:
120                   op = self.Parse(data, dry_run)
121                   self.assert_(isinstance(op, opcodes.OpInstanceCreate))
122                   self.assertEqual(op.mode, mode)
123                   self.assertEqual(op.disk_template, disk_template)
124                   self.assertEqual(op.dry_run, dry_run)
125                   self.assertEqual(len(op.disks), len(disks))
126                   self.assertEqual(len(op.nics), len(nics))
127
128                   for opdisk, disk in zip(op.disks, disks):
129                     for key in constants.IDISK_PARAMS:
130                       self.assertEqual(opdisk.get(key), disk.get(key))
131                     self.assertFalse("unknown" in opdisk)
132
133                   for opnic, nic in zip(op.nics, nics):
134                     for key in constants.INIC_PARAMS:
135                       self.assertEqual(opnic.get(key), nic.get(key))
136                     self.assertFalse("unknown" in opnic)
137                     self.assertFalse("foobar" in opnic)
138
139                   if beparams is None:
140                     self.assertEqualValues(op.beparams, {})
141                   else:
142                     self.assertEqualValues(op.beparams, beparams)
143
144                   if hvparams is None:
145                     self.assertEqualValues(op.hvparams, {})
146                   else:
147                     self.assertEqualValues(op.hvparams, hvparams)
148
149   def testErrors(self):
150     # Test all required fields
151     reqfields = {
152       "name": "inst1.example.com",
153       "disks": [],
154       "nics": [],
155       "mode": constants.INSTANCE_CREATE,
156       "disk_template": constants.DT_PLAIN,
157       "os": "debootstrap",
158       }
159
160     for name in reqfields.keys():
161       self.assertRaises(http.HttpBadRequest, self.Parse,
162                         dict(i for i in reqfields.iteritems() if i[0] != name),
163                         False)
164
165     # Invalid disks and nics
166     for field in ["disks", "nics"]:
167       invalid_values = [None, 1, "", {}, [1, 2, 3], ["hda1", "hda2"]]
168
169       if field == "disks":
170         invalid_values.append([
171           # Disks without size
172           {},
173           { "mode": constants.DISK_RDWR, },
174           ])
175
176       for invvalue in invalid_values:
177         data = reqfields.copy()
178         data[field] = invvalue
179         self.assertRaises(http.HttpBadRequest, self.Parse, data, False)
180
181
182 class TestParseExportInstanceRequest(testutils.GanetiTestCase):
183   def setUp(self):
184     testutils.GanetiTestCase.setUp(self)
185
186     self.Parse = rlib2._ParseExportInstanceRequest
187
188   def test(self):
189     name = "instmoo"
190     data = {
191       "mode": constants.EXPORT_MODE_REMOTE,
192       "destination": [(1, 2, 3), (99, 99, 99)],
193       "shutdown": True,
194       "remove_instance": True,
195       "x509_key_name": ["name", "hash"],
196       "destination_x509_ca": "---cert---"
197       }
198     op = self.Parse(name, data)
199     self.assert_(isinstance(op, opcodes.OpBackupExport))
200     self.assertEqual(op.instance_name, name)
201     self.assertEqual(op.mode, constants.EXPORT_MODE_REMOTE)
202     self.assertEqual(op.shutdown, True)
203     self.assertEqual(op.remove_instance, True)
204     self.assertEqualValues(op.x509_key_name, ("name", "hash"))
205     self.assertEqual(op.destination_x509_ca, "---cert---")
206
207   def testDefaults(self):
208     name = "inst1"
209     data = {
210       "destination": "node2",
211       "shutdown": False,
212       }
213     op = self.Parse(name, data)
214     self.assert_(isinstance(op, opcodes.OpBackupExport))
215     self.assertEqual(op.instance_name, name)
216     self.assertEqual(op.target_node, "node2")
217     self.assertFalse(hasattr(op, "mode"))
218     self.assertFalse(hasattr(op, "remove_instance"))
219     self.assertFalse(hasattr(op, "destination"))
220
221   def testErrors(self):
222     self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
223                       { "remove_instance": "True", })
224     self.assertRaises(http.HttpBadRequest, self.Parse, "err1",
225                       { "remove_instance": "False", })
226
227
228 class TestParseMigrateInstanceRequest(testutils.GanetiTestCase):
229   def setUp(self):
230     testutils.GanetiTestCase.setUp(self)
231
232     self.Parse = rlib2._ParseMigrateInstanceRequest
233
234   def test(self):
235     name = "instYooho6ek"
236
237     for cleanup in [False, True]:
238       for mode in constants.HT_MIGRATION_MODES:
239         data = {
240           "cleanup": cleanup,
241           "mode": mode,
242           }
243         op = self.Parse(name, data)
244         self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
245         self.assertEqual(op.instance_name, name)
246         self.assertEqual(op.mode, mode)
247         self.assertEqual(op.cleanup, cleanup)
248
249   def testDefaults(self):
250     name = "instnohZeex0"
251
252     op = self.Parse(name, {})
253     self.assert_(isinstance(op, opcodes.OpInstanceMigrate))
254     self.assertEqual(op.instance_name, name)
255     self.assertFalse(hasattr(op, "mode"))
256     self.assertFalse(hasattr(op, "cleanup"))
257
258
259 class TestParseRenameInstanceRequest(testutils.GanetiTestCase):
260   def setUp(self):
261     testutils.GanetiTestCase.setUp(self)
262
263     self.Parse = rlib2._ParseRenameInstanceRequest
264
265   def test(self):
266     name = "instij0eeph7"
267
268     for new_name in ["ua0aiyoo", "fai3ongi"]:
269       for ip_check in [False, True]:
270         for name_check in [False, True]:
271           data = {
272             "new_name": new_name,
273             "ip_check": ip_check,
274             "name_check": name_check,
275             }
276
277           op = self.Parse(name, data)
278           self.assert_(isinstance(op, opcodes.OpInstanceRename))
279           self.assertEqual(op.instance_name, name)
280           self.assertEqual(op.new_name, new_name)
281           self.assertEqual(op.ip_check, ip_check)
282           self.assertEqual(op.name_check, name_check)
283
284   def testDefaults(self):
285     name = "instahchie3t"
286
287     for new_name in ["thag9mek", "quees7oh"]:
288       data = {
289         "new_name": new_name,
290         }
291
292       op = self.Parse(name, data)
293       self.assert_(isinstance(op, opcodes.OpInstanceRename))
294       self.assertEqual(op.instance_name, name)
295       self.assertEqual(op.new_name, new_name)
296       self.assertFalse(hasattr(op, "ip_check"))
297       self.assertFalse(hasattr(op, "name_check"))
298
299
300 class TestParseModifyInstanceRequest(testutils.GanetiTestCase):
301   def setUp(self):
302     testutils.GanetiTestCase.setUp(self)
303
304     self.Parse = rlib2._ParseModifyInstanceRequest
305
306   def test(self):
307     name = "instush8gah"
308
309     test_disks = [
310       [],
311       [(1, { constants.IDISK_MODE: constants.DISK_RDWR, })],
312       ]
313
314     for osparams in [{}, { "some": "value", "other": "Hello World", }]:
315       for hvparams in [{}, { constants.HV_KERNEL_PATH: "/some/kernel", }]:
316         for beparams in [{}, { constants.BE_MEMORY: 128, }]:
317           for force in [False, True]:
318             for nics in [[], [(0, { constants.INIC_IP: "192.0.2.1", })]]:
319               for disks in test_disks:
320                 for disk_template in constants.DISK_TEMPLATES:
321                   data = {
322                     "osparams": osparams,
323                     "hvparams": hvparams,
324                     "beparams": beparams,
325                     "nics": nics,
326                     "disks": disks,
327                     "force": force,
328                     "disk_template": disk_template,
329                     }
330
331                   op = self.Parse(name, data)
332                   self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
333                   self.assertEqual(op.instance_name, name)
334                   self.assertEqual(op.hvparams, hvparams)
335                   self.assertEqual(op.beparams, beparams)
336                   self.assertEqual(op.osparams, osparams)
337                   self.assertEqual(op.force, force)
338                   self.assertEqual(op.nics, nics)
339                   self.assertEqual(op.disks, disks)
340                   self.assertEqual(op.disk_template, disk_template)
341                   self.assertFalse(hasattr(op, "remote_node"))
342                   self.assertFalse(hasattr(op, "os_name"))
343                   self.assertFalse(hasattr(op, "force_variant"))
344
345   def testDefaults(self):
346     name = "instir8aish31"
347
348     op = self.Parse(name, {})
349     self.assert_(isinstance(op, opcodes.OpInstanceSetParams))
350     self.assertEqual(op.instance_name, name)
351     for i in ["hvparams", "beparams", "osparams", "force", "nics", "disks",
352               "disk_template", "remote_node", "os_name", "force_variant"]:
353       self.assertFalse(hasattr(op, i))
354
355
356 class TestParseInstanceReinstallRequest(testutils.GanetiTestCase):
357   def setUp(self):
358     testutils.GanetiTestCase.setUp(self)
359
360     self.Parse = rlib2._ParseInstanceReinstallRequest
361
362   def _Check(self, ops, name):
363     expcls = [
364       opcodes.OpInstanceShutdown,
365       opcodes.OpInstanceReinstall,
366       opcodes.OpInstanceStartup,
367       ]
368
369     self.assert_(compat.all(isinstance(op, exp)
370                             for op, exp in zip(ops, expcls)))
371     self.assert_(compat.all(op.instance_name == name for op in ops))
372
373   def test(self):
374     name = "shoo0tihohma"
375
376     ops = self.Parse(name, {"os": "sys1", "start": True,})
377     self.assertEqual(len(ops), 3)
378     self._Check(ops, name)
379     self.assertEqual(ops[1].os_type, "sys1")
380     self.assertFalse(ops[1].osparams)
381
382     ops = self.Parse(name, {"os": "sys2", "start": False,})
383     self.assertEqual(len(ops), 2)
384     self._Check(ops, name)
385     self.assertEqual(ops[1].os_type, "sys2")
386
387     osparams = {
388       "reformat": "1",
389       }
390     ops = self.Parse(name, {"os": "sys4035", "start": True,
391                             "osparams": osparams,})
392     self.assertEqual(len(ops), 3)
393     self._Check(ops, name)
394     self.assertEqual(ops[1].os_type, "sys4035")
395     self.assertEqual(ops[1].osparams, osparams)
396
397   def testDefaults(self):
398     name = "noolee0g"
399
400     ops = self.Parse(name, {"os": "linux1"})
401     self.assertEqual(len(ops), 3)
402     self._Check(ops, name)
403     self.assertEqual(ops[1].os_type, "linux1")
404     self.assertFalse(ops[1].osparams)
405
406
407 class TestParseRenameGroupRequest(testutils.GanetiTestCase):
408   def setUp(self):
409     testutils.GanetiTestCase.setUp(self)
410
411     self.Parse = rlib2._ParseRenameGroupRequest
412
413   def test(self):
414     name = "instij0eeph7"
415     data = {
416       "new_name": "ua0aiyoo",
417       }
418
419     op = self.Parse(name, data, False)
420
421     self.assert_(isinstance(op, opcodes.OpGroupRename))
422     self.assertEqual(op.old_name, name)
423     self.assertEqual(op.new_name, "ua0aiyoo")
424     self.assertFalse(op.dry_run)
425
426   def testDryRun(self):
427     name = "instij0eeph7"
428     data = {
429       "new_name": "ua0aiyoo",
430       }
431
432     op = self.Parse(name, data, True)
433
434     self.assert_(isinstance(op, opcodes.OpGroupRename))
435     self.assertEqual(op.old_name, name)
436     self.assertEqual(op.new_name, "ua0aiyoo")
437     self.assert_(op.dry_run)
438
439
440 class TestParseInstanceReplaceDisksRequest(unittest.TestCase):
441   def setUp(self):
442     self.Parse = rlib2._ParseInstanceReplaceDisksRequest
443
444   def test(self):
445     name = "inst22568"
446
447     for disks in [range(1, 4), "1,2,3", "1, 2, 3"]:
448       data = {
449         "mode": constants.REPLACE_DISK_SEC,
450         "disks": disks,
451         "iallocator": "myalloc",
452         }
453
454       op = self.Parse(name, data)
455       self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
456       self.assertEqual(op.mode, constants.REPLACE_DISK_SEC)
457       self.assertEqual(op.disks, [1, 2, 3])
458       self.assertEqual(op.iallocator, "myalloc")
459
460   def testDefaults(self):
461     name = "inst11413"
462     data = {
463       "mode": constants.REPLACE_DISK_AUTO,
464       }
465
466     op = self.Parse(name, data)
467     self.assert_(isinstance(op, opcodes.OpInstanceReplaceDisks))
468     self.assertEqual(op.mode, constants.REPLACE_DISK_AUTO)
469     self.assertFalse(hasattr(op, "iallocator"))
470     self.assertFalse(hasattr(op, "disks"))
471
472   def testWrong(self):
473     self.assertRaises(http.HttpBadRequest, self.Parse, "inst",
474                       { "mode": constants.REPLACE_DISK_AUTO,
475                         "disks": "hello world",
476                       })
477
478
479 if __name__ == '__main__':
480   testutils.GanetiTestProgram()