Merge branch 'stable-2.8' into stable-2.9
[ganeti-local] / test / py / ganeti.config_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 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 config module"""
23
24
25 import unittest
26 import os
27 import tempfile
28 import operator
29
30 from ganeti import bootstrap
31 from ganeti import config
32 from ganeti import constants
33 from ganeti import errors
34 from ganeti import objects
35 from ganeti import utils
36 from ganeti import netutils
37 from ganeti import compat
38 from ganeti.cmdlib import instance
39
40 from ganeti.config import TemporaryReservationManager
41
42 import testutils
43 import mocks
44 import mock
45
46
47 def _StubGetEntResolver():
48   return mocks.FakeGetentResolver()
49
50
51 class TestConfigRunner(unittest.TestCase):
52   """Testing case for HooksRunner"""
53   def setUp(self):
54     fd, self.cfg_file = tempfile.mkstemp()
55     os.close(fd)
56     self._init_cluster(self.cfg_file)
57
58   def tearDown(self):
59     try:
60       os.unlink(self.cfg_file)
61     except OSError:
62       pass
63
64   def _get_object(self):
65     """Returns an instance of ConfigWriter"""
66     cfg = config.ConfigWriter(cfg_file=self.cfg_file, offline=True,
67                               _getents=_StubGetEntResolver)
68     return cfg
69
70   def _init_cluster(self, cfg):
71     """Initializes the cfg object"""
72     me = netutils.Hostname()
73     ip = constants.IP4_ADDRESS_LOCALHOST
74     # master_ip must not conflict with the node ip address
75     master_ip = "127.0.0.2"
76
77     cluster_config = objects.Cluster(
78       serial_no=1,
79       rsahostkeypub="",
80       dsahostkeypub="",
81       highest_used_port=(constants.FIRST_DRBD_PORT - 1),
82       mac_prefix="aa:00:00",
83       volume_group_name="xenvg",
84       drbd_usermode_helper="/bin/true",
85       nicparams={constants.PP_DEFAULT: constants.NICC_DEFAULTS},
86       ndparams=constants.NDC_DEFAULTS,
87       tcpudp_port_pool=set(),
88       enabled_hypervisors=[constants.HT_FAKE],
89       master_node=me.name,
90       master_ip=master_ip,
91       master_netdev=constants.DEFAULT_BRIDGE,
92       cluster_name="cluster.local",
93       file_storage_dir="/tmp",
94       uid_pool=[],
95       )
96
97     master_node_config = objects.Node(name=me.name,
98                                       primary_ip=me.ip,
99                                       secondary_ip=ip,
100                                       serial_no=1,
101                                       master_candidate=True)
102
103     bootstrap.InitConfig(constants.CONFIG_VERSION,
104                          cluster_config, master_node_config, self.cfg_file)
105
106   def _create_instance(self):
107     """Create and return an instance object"""
108     inst = objects.Instance(name="test.example.com",
109                             uuid="test-uuid",
110                             disks=[], nics=[],
111                             disk_template=constants.DT_DISKLESS,
112                             primary_node=self._get_object().GetMasterNode())
113     return inst
114
115   def testEmpty(self):
116     """Test instantiate config object"""
117     self._get_object()
118
119   def testInit(self):
120     """Test initialize the config file"""
121     cfg = self._get_object()
122     self.failUnlessEqual(1, len(cfg.GetNodeList()))
123     self.failUnlessEqual(0, len(cfg.GetInstanceList()))
124
125   def testUpdateCluster(self):
126     """Test updates on the cluster object"""
127     cfg = self._get_object()
128     # construct a fake cluster object
129     fake_cl = objects.Cluster()
130     # fail if we didn't read the config
131     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
132
133     cl = cfg.GetClusterInfo()
134     # first pass, must not fail
135     cfg.Update(cl, None)
136     # second pass, also must not fail (after the config has been written)
137     cfg.Update(cl, None)
138     # but the fake_cl update should still fail
139     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl, None)
140
141   def testUpdateNode(self):
142     """Test updates on one node object"""
143     cfg = self._get_object()
144     # construct a fake node
145     fake_node = objects.Node()
146     # fail if we didn't read the config
147     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_node,
148                           None)
149
150     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
151     # first pass, must not fail
152     cfg.Update(node, None)
153     # second pass, also must not fail (after the config has been written)
154     cfg.Update(node, None)
155     # but the fake_node update should still fail
156     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_node,
157                           None)
158
159   def testUpdateInstance(self):
160     """Test updates on one instance object"""
161     cfg = self._get_object()
162     # construct a fake instance
163     inst = self._create_instance()
164     fake_instance = objects.Instance()
165     # fail if we didn't read the config
166     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance,
167                           None)
168
169     cfg.AddInstance(inst, "my-job")
170     instance = cfg.GetInstanceInfo(cfg.GetInstanceList()[0])
171     # first pass, must not fail
172     cfg.Update(instance, None)
173     # second pass, also must not fail (after the config has been written)
174     cfg.Update(instance, None)
175     # but the fake_instance update should still fail
176     self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance,
177                           None)
178
179   def testUpgradeSave(self):
180     """Test that any modification done during upgrading is saved back"""
181     cfg = self._get_object()
182
183     # Remove an element, run upgrade, and check if the element is
184     # back and the file upgraded
185     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
186     # For a ConfigObject, None is the same as a missing field
187     node.ndparams = None
188     oldsaved = utils.ReadFile(self.cfg_file)
189     cfg._UpgradeConfig()
190     self.assertTrue(node.ndparams is not None)
191     newsaved = utils.ReadFile(self.cfg_file)
192     # We rely on the fact that at least the serial number changes
193     self.assertNotEqual(oldsaved, newsaved)
194
195     # Add something that should not be there this time
196     key = list(constants.NDC_GLOBALS)[0]
197     node.ndparams[key] = constants.NDC_DEFAULTS[key]
198     cfg._WriteConfig(None)
199     oldsaved = utils.ReadFile(self.cfg_file)
200     cfg._UpgradeConfig()
201     self.assertTrue(node.ndparams.get(key) is None)
202     newsaved = utils.ReadFile(self.cfg_file)
203     self.assertNotEqual(oldsaved, newsaved)
204
205     # Do the upgrade again, this time there should be no update
206     oldsaved = newsaved
207     cfg._UpgradeConfig()
208     newsaved = utils.ReadFile(self.cfg_file)
209     self.assertEqual(oldsaved, newsaved)
210
211     # Reload the configuration again: it shouldn't change the file
212     oldsaved = newsaved
213     self._get_object()
214     newsaved = utils.ReadFile(self.cfg_file)
215     self.assertEqual(oldsaved, newsaved)
216
217   def testNICParameterSyntaxCheck(self):
218     """Test the NIC's CheckParameterSyntax function"""
219     mode = constants.NIC_MODE
220     link = constants.NIC_LINK
221     m_bridged = constants.NIC_MODE_BRIDGED
222     m_routed = constants.NIC_MODE_ROUTED
223     CheckSyntax = objects.NIC.CheckParameterSyntax
224
225     CheckSyntax(constants.NICC_DEFAULTS)
226     CheckSyntax({mode: m_bridged, link: "br1"})
227     CheckSyntax({mode: m_routed, link: "default"})
228     self.assertRaises(errors.ConfigurationError,
229                       CheckSyntax, {mode: "000invalid", link: "any"})
230     self.assertRaises(errors.ConfigurationError,
231                       CheckSyntax, {mode: m_bridged, link: None})
232     self.assertRaises(errors.ConfigurationError,
233                       CheckSyntax, {mode: m_bridged, link: ""})
234
235   def testGetNdParamsDefault(self):
236     cfg = self._get_object()
237     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
238     self.assertEqual(cfg.GetNdParams(node), constants.NDC_DEFAULTS)
239
240   def testGetNdParamsModifiedNode(self):
241     my_ndparams = {
242         constants.ND_OOB_PROGRAM: "/bin/node-oob",
243         constants.ND_SPINDLE_COUNT: 1,
244         constants.ND_EXCLUSIVE_STORAGE: False,
245         }
246
247     cfg = self._get_object()
248     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
249     node.ndparams = my_ndparams
250     cfg.Update(node, None)
251     self.assertEqual(cfg.GetNdParams(node), my_ndparams)
252
253   def testGetNdParamsInheritance(self):
254     node_ndparams = {
255       constants.ND_OOB_PROGRAM: "/bin/node-oob",
256       }
257     group_ndparams = {
258       constants.ND_SPINDLE_COUNT: 10,
259       }
260     expected_ndparams = {
261       constants.ND_OOB_PROGRAM: "/bin/node-oob",
262       constants.ND_SPINDLE_COUNT: 10,
263       constants.ND_EXCLUSIVE_STORAGE:
264         constants.NDC_DEFAULTS[constants.ND_EXCLUSIVE_STORAGE],
265       }
266     cfg = self._get_object()
267     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
268     node.ndparams = node_ndparams
269     cfg.Update(node, None)
270     group = cfg.GetNodeGroup(node.group)
271     group.ndparams = group_ndparams
272     cfg.Update(group, None)
273     self.assertEqual(cfg.GetNdParams(node), expected_ndparams)
274
275   def testAddGroupFillsFieldsIfMissing(self):
276     cfg = self._get_object()
277     group = objects.NodeGroup(name="test", members=[])
278     cfg.AddNodeGroup(group, "my-job")
279     self.assert_(utils.UUID_RE.match(group.uuid))
280     self.assertEqual(constants.ALLOC_POLICY_PREFERRED, group.alloc_policy)
281
282   def testAddGroupPreservesFields(self):
283     cfg = self._get_object()
284     group = objects.NodeGroup(name="test", members=[],
285                               alloc_policy=constants.ALLOC_POLICY_LAST_RESORT)
286     cfg.AddNodeGroup(group, "my-job")
287     self.assertEqual(constants.ALLOC_POLICY_LAST_RESORT, group.alloc_policy)
288
289   def testAddGroupDoesNotPreserveFields(self):
290     cfg = self._get_object()
291     group = objects.NodeGroup(name="test", members=[],
292                               serial_no=17, ctime=123, mtime=456)
293     cfg.AddNodeGroup(group, "my-job")
294     self.assertEqual(1, group.serial_no)
295     self.assert_(group.ctime > 1200000000)
296     self.assert_(group.mtime > 1200000000)
297
298   def testAddGroupCanSkipUUIDCheck(self):
299     cfg = self._get_object()
300     uuid = cfg.GenerateUniqueID("my-job")
301     group = objects.NodeGroup(name="test", members=[], uuid=uuid,
302                               serial_no=17, ctime=123, mtime=456)
303
304     self.assertRaises(errors.ConfigurationError,
305                       cfg.AddNodeGroup, group, "my-job")
306
307     cfg.AddNodeGroup(group, "my-job", check_uuid=False) # Does not raise.
308     self.assertEqual(uuid, group.uuid)
309
310   def testAssignGroupNodes(self):
311     me = netutils.Hostname()
312     cfg = self._get_object()
313
314     # Create two groups
315     grp1 = objects.NodeGroup(name="grp1", members=[],
316                              uuid="2f2fadf7-2a70-4a23-9ab5-2568c252032c")
317     grp1_serial = 1
318     cfg.AddNodeGroup(grp1, "job")
319
320     grp2 = objects.NodeGroup(name="grp2", members=[],
321                              uuid="798d0de3-680f-4a0e-b29a-0f54f693b3f1")
322     grp2_serial = 1
323     cfg.AddNodeGroup(grp2, "job")
324     self.assertEqual(set(map(operator.attrgetter("name"),
325                              cfg.GetAllNodeGroupsInfo().values())),
326                      set(["grp1", "grp2", constants.INITIAL_NODE_GROUP_NAME]))
327
328     # No-op
329     cluster_serial = cfg.GetClusterInfo().serial_no
330     cfg.AssignGroupNodes([])
331     cluster_serial += 1
332
333     # Create two nodes
334     node1 = objects.Node(name="node1", group=grp1.uuid, ndparams={},
335                          uuid="node1-uuid")
336     node1_serial = 1
337     node2 = objects.Node(name="node2", group=grp2.uuid, ndparams={},
338                          uuid="node2-uuid")
339     node2_serial = 1
340     cfg.AddNode(node1, "job")
341     cfg.AddNode(node2, "job")
342     cluster_serial += 2
343     self.assertEqual(set(cfg.GetNodeList()),
344                      set(["node1-uuid", "node2-uuid",
345                           cfg.GetNodeInfoByName(me.name).uuid]))
346
347     def _VerifySerials():
348       self.assertEqual(cfg.GetClusterInfo().serial_no, cluster_serial)
349       self.assertEqual(node1.serial_no, node1_serial)
350       self.assertEqual(node2.serial_no, node2_serial)
351       self.assertEqual(grp1.serial_no, grp1_serial)
352       self.assertEqual(grp2.serial_no, grp2_serial)
353
354     _VerifySerials()
355
356     self.assertEqual(set(grp1.members), set(["node1-uuid"]))
357     self.assertEqual(set(grp2.members), set(["node2-uuid"]))
358
359     # Check invalid nodes and groups
360     self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
361       ("unknown.node.example.com", grp2.uuid),
362       ])
363     self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
364       (node1.name, "unknown-uuid"),
365       ])
366
367     self.assertEqual(node1.group, grp1.uuid)
368     self.assertEqual(node2.group, grp2.uuid)
369     self.assertEqual(set(grp1.members), set(["node1-uuid"]))
370     self.assertEqual(set(grp2.members), set(["node2-uuid"]))
371
372     # Another no-op
373     cfg.AssignGroupNodes([])
374     cluster_serial += 1
375     _VerifySerials()
376
377     # Assign to the same group (should be a no-op)
378     self.assertEqual(node2.group, grp2.uuid)
379     cfg.AssignGroupNodes([
380       (node2.uuid, grp2.uuid),
381       ])
382     cluster_serial += 1
383     self.assertEqual(node2.group, grp2.uuid)
384     _VerifySerials()
385     self.assertEqual(set(grp1.members), set(["node1-uuid"]))
386     self.assertEqual(set(grp2.members), set(["node2-uuid"]))
387
388     # Assign node 2 to group 1
389     self.assertEqual(node2.group, grp2.uuid)
390     cfg.AssignGroupNodes([
391       (node2.uuid, grp1.uuid),
392       ])
393     cluster_serial += 1
394     node2_serial += 1
395     grp1_serial += 1
396     grp2_serial += 1
397     self.assertEqual(node2.group, grp1.uuid)
398     _VerifySerials()
399     self.assertEqual(set(grp1.members), set(["node1-uuid", "node2-uuid"]))
400     self.assertFalse(grp2.members)
401
402     # And assign both nodes to group 2
403     self.assertEqual(node1.group, grp1.uuid)
404     self.assertEqual(node2.group, grp1.uuid)
405     self.assertNotEqual(grp1.uuid, grp2.uuid)
406     cfg.AssignGroupNodes([
407       (node1.uuid, grp2.uuid),
408       (node2.uuid, grp2.uuid),
409       ])
410     cluster_serial += 1
411     node1_serial += 1
412     node2_serial += 1
413     grp1_serial += 1
414     grp2_serial += 1
415     self.assertEqual(node1.group, grp2.uuid)
416     self.assertEqual(node2.group, grp2.uuid)
417     _VerifySerials()
418     self.assertFalse(grp1.members)
419     self.assertEqual(set(grp2.members), set(["node1-uuid", "node2-uuid"]))
420
421     # Destructive tests
422     orig_group = node2.group
423     try:
424       other_uuid = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
425       assert compat.all(node.group != other_uuid
426                         for node in cfg.GetAllNodesInfo().values())
427       node2.group = "68b3d087-6ea5-491c-b81f-0a47d90228c5"
428       self.assertRaises(errors.ConfigurationError, cfg.AssignGroupNodes, [
429         (node2.uuid, grp2.uuid),
430         ])
431       _VerifySerials()
432     finally:
433       node2.group = orig_group
434
435   def _TestVerifyConfigIPolicy(self, ipolicy, ipowner, cfg, isgroup):
436     INVALID_KEY = "this_key_cannot_exist"
437
438     ipolicy[INVALID_KEY] = None
439     # A call to cluster.SimpleFillIPolicy causes different kinds of error
440     # depending on the owner (cluster or group)
441     if isgroup:
442       errs = cfg.VerifyConfig()
443       self.assertTrue(len(errs) >= 1)
444       errstr = "%s has invalid instance policy" % ipowner
445       self.assertTrue(_IsErrorInList(errstr, errs))
446     else:
447       self.assertRaises(AssertionError, cfg.VerifyConfig)
448     del ipolicy[INVALID_KEY]
449     errs = cfg.VerifyConfig()
450     self.assertFalse(errs)
451
452     key = list(constants.IPOLICY_PARAMETERS)[0]
453     hasoldv = (key in ipolicy)
454     if hasoldv:
455       oldv = ipolicy[key]
456     ipolicy[key] = "blah"
457     errs = cfg.VerifyConfig()
458     self.assertTrue(len(errs) >= 1)
459     self.assertTrue(_IsErrorInList("%s has invalid instance policy" % ipowner,
460                                    errs))
461     if hasoldv:
462       ipolicy[key] = oldv
463     else:
464       del ipolicy[key]
465
466     ispeclist = []
467     if constants.ISPECS_MINMAX in ipolicy:
468       for k in range(len(ipolicy[constants.ISPECS_MINMAX])):
469         ispeclist.extend([
470             (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MIN],
471              "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MIN)),
472             (ipolicy[constants.ISPECS_MINMAX][k][constants.ISPECS_MAX],
473              "%s[%s]/%s" % (constants.ISPECS_MINMAX, k, constants.ISPECS_MAX)),
474             ])
475     if constants.ISPECS_STD in ipolicy:
476       ispeclist.append((ipolicy[constants.ISPECS_STD], constants.ISPECS_STD))
477
478     for (ispec, ispecpath) in ispeclist:
479       ispec[INVALID_KEY] = None
480       errs = cfg.VerifyConfig()
481       self.assertTrue(len(errs) >= 1)
482       self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
483                                       (ipowner, ispecpath)), errs))
484       del ispec[INVALID_KEY]
485       errs = cfg.VerifyConfig()
486       self.assertFalse(errs)
487
488       for par in constants.ISPECS_PARAMETERS:
489         hasoldv = par in ispec
490         if hasoldv:
491           oldv = ispec[par]
492         ispec[par] = "blah"
493         errs = cfg.VerifyConfig()
494         self.assertTrue(len(errs) >= 1)
495         self.assertTrue(_IsErrorInList(("%s has invalid ipolicy/%s" %
496                                         (ipowner, ispecpath)), errs))
497         if hasoldv:
498           ispec[par] = oldv
499         else:
500           del ispec[par]
501         errs = cfg.VerifyConfig()
502         self.assertFalse(errs)
503
504     if constants.ISPECS_MINMAX in ipolicy:
505       # Test partial minmax specs
506       for minmax in ipolicy[constants.ISPECS_MINMAX]:
507         for key in constants.ISPECS_MINMAX_KEYS:
508           self.assertTrue(key in minmax)
509           ispec = minmax[key]
510           del minmax[key]
511           errs = cfg.VerifyConfig()
512           self.assertTrue(len(errs) >= 1)
513           self.assertTrue(_IsErrorInList("Missing instance specification",
514                                          errs))
515           minmax[key] = ispec
516           for par in constants.ISPECS_PARAMETERS:
517             oldv = ispec[par]
518             del ispec[par]
519             errs = cfg.VerifyConfig()
520             self.assertTrue(len(errs) >= 1)
521             self.assertTrue(_IsErrorInList("Missing instance specs parameters",
522                                            errs))
523             ispec[par] = oldv
524       errs = cfg.VerifyConfig()
525       self.assertFalse(errs)
526
527   def _TestVerifyConfigGroupIPolicy(self, groupinfo, cfg):
528     old_ipolicy = groupinfo.ipolicy
529     ipolicy = cfg.GetClusterInfo().SimpleFillIPolicy({})
530     groupinfo.ipolicy = ipolicy
531     # Test partial policies
532     for key in constants.IPOLICY_ALL_KEYS:
533       self.assertTrue(key in ipolicy)
534       oldv = ipolicy[key]
535       del ipolicy[key]
536       errs = cfg.VerifyConfig()
537       self.assertFalse(errs)
538       ipolicy[key] = oldv
539     groupinfo.ipolicy = old_ipolicy
540
541   def _TestVerifyConfigClusterIPolicy(self, ipolicy, cfg):
542     # Test partial policies
543     for key in constants.IPOLICY_ALL_KEYS:
544       self.assertTrue(key in ipolicy)
545       oldv = ipolicy[key]
546       del ipolicy[key]
547       self.assertRaises(AssertionError, cfg.VerifyConfig)
548       ipolicy[key] = oldv
549     errs = cfg.VerifyConfig()
550     self.assertFalse(errs)
551     # Partial standard specs
552     ispec = ipolicy[constants.ISPECS_STD]
553     for par in constants.ISPECS_PARAMETERS:
554       oldv = ispec[par]
555       del ispec[par]
556       errs = cfg.VerifyConfig()
557       self.assertTrue(len(errs) >= 1)
558       self.assertTrue(_IsErrorInList("Missing instance specs parameters",
559                                      errs))
560       ispec[par] = oldv
561     errs = cfg.VerifyConfig()
562     self.assertFalse(errs)
563
564   def testVerifyConfig(self):
565     cfg = self._get_object()
566
567     errs = cfg.VerifyConfig()
568     self.assertFalse(errs)
569
570     node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
571     key = list(constants.NDC_GLOBALS)[0]
572     node.ndparams[key] = constants.NDC_DEFAULTS[key]
573     errs = cfg.VerifyConfig()
574     self.assertTrue(len(errs) >= 1)
575     self.assertTrue(_IsErrorInList("has some global parameters set", errs))
576
577     del node.ndparams[key]
578     errs = cfg.VerifyConfig()
579     self.assertFalse(errs)
580
581     cluster = cfg.GetClusterInfo()
582     nodegroup = cfg.GetNodeGroup(cfg.GetNodeGroupList()[0])
583     self._TestVerifyConfigIPolicy(cluster.ipolicy, "cluster", cfg, False)
584     self._TestVerifyConfigClusterIPolicy(cluster.ipolicy, cfg)
585     self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
586     self._TestVerifyConfigGroupIPolicy(nodegroup, cfg)
587     nodegroup.ipolicy = cluster.SimpleFillIPolicy(nodegroup.ipolicy)
588     self._TestVerifyConfigIPolicy(nodegroup.ipolicy, nodegroup.name, cfg, True)
589
590   # Tests for Ssconf helper functions
591   def testUnlockedGetHvparamsString(self):
592     hvparams = {"a": "A", "b": "B", "c": "C"}
593     hvname = "myhv"
594     cfg_writer = self._get_object()
595     cfg_writer._config_data = mock.Mock()
596     cfg_writer._config_data.cluster = mock.Mock()
597     cfg_writer._config_data.cluster.hvparams = {hvname: hvparams}
598
599     result = cfg_writer._UnlockedGetHvparamsString(hvname)
600
601     self.assertTrue("a=A" in result)
602     lines = [line for line in result.split('\n') if line != '']
603     self.assertEqual(len(hvparams.keys()), len(lines))
604
605   def testExtendByAllHvparamsStrings(self):
606     all_hvparams = {constants.HT_XEN_PVM: "foo"}
607     ssconf_values = {}
608     cfg_writer = self._get_object()
609
610     cfg_writer._ExtendByAllHvparamsStrings(ssconf_values, all_hvparams)
611
612     expected_key = constants.SS_HVPARAMS_PREF + constants.HT_XEN_PVM
613     self.assertTrue(expected_key in ssconf_values)
614
615
616 def _IsErrorInList(err_str, err_list):
617   return any(map(lambda e: err_str in e, err_list))
618
619
620 class TestTRM(unittest.TestCase):
621   EC_ID = 1
622
623   def testEmpty(self):
624     t = TemporaryReservationManager()
625     t.Reserve(self.EC_ID, "a")
626     self.assertFalse(t.Reserved(self.EC_ID))
627     self.assertTrue(t.Reserved("a"))
628     self.assertEqual(len(t.GetReserved()), 1)
629
630   def testDuplicate(self):
631     t = TemporaryReservationManager()
632     t.Reserve(self.EC_ID, "a")
633     self.assertRaises(errors.ReservationError, t.Reserve, 2, "a")
634     t.DropECReservations(self.EC_ID)
635     self.assertFalse(t.Reserved("a"))
636
637
638 class TestCheckInstanceDiskIvNames(unittest.TestCase):
639   @staticmethod
640   def _MakeDisks(names):
641     return [objects.Disk(iv_name=name) for name in names]
642
643   def testNoError(self):
644     disks = self._MakeDisks(["disk/0", "disk/1"])
645     self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
646     instance._UpdateIvNames(0, disks)
647     self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
648
649   def testWrongNames(self):
650     disks = self._MakeDisks(["disk/1", "disk/3", "disk/2"])
651     self.assertEqual(config._CheckInstanceDiskIvNames(disks), [
652       (0, "disk/0", "disk/1"),
653       (1, "disk/1", "disk/3"),
654       ])
655
656     # Fix names
657     instance._UpdateIvNames(0, disks)
658     self.assertEqual(config._CheckInstanceDiskIvNames(disks), [])
659
660
661 if __name__ == "__main__":
662   testutils.GanetiTestProgram()