if not isinstance(instance, objects.Instance):
raise errors.ProgrammerError("Invalid type passed to AddInstance")
- all_lvs = instance.MapLVsByNode()
- logger.Info("Instance '%s' DISK_LAYOUT: %s" % (instance.name, all_lvs))
+ if instance.disk_template != constants.DT_DISKLESS:
+ all_lvs = instance.MapLVsByNode()
+ logger.Info("Instance '%s' DISK_LAYOUT: %s" % (instance.name, all_lvs))
self._OpenConfig()
self._config_data.instances[instance.name] = instance
self._ReleaseLock()
return self._config_data.cluster
+
+ def Update(self, target):
+ """Notify function to be called after updates.
+
+ This function must be called when an object (as returned by
+ GetInstanceInfo, GetNodeInfo, GetCluster) has been updated and the
+ caller wants the modifications saved to the backing store. Note
+ that all modified objects will be saved, but the target argument
+ is the one the caller wants to ensure that it's saved.
+
+ """
+ if self._config_data is None:
+ raise errors.ProgrammerError, ("Configuration file not read,"
+ " cannot save.")
+ if isinstance(target, objects.Cluster):
+ test = target == self._config_data.cluster
+ elif isinstance(target, objects.Node):
+ test = target in self._config_data.nodes.values()
+ elif isinstance(target, objects.Instance):
+ test = target in self._config_data.instances.values()
+ else:
+ raise errors.ProgrammerError, ("Invalid object type (%s) passed to"
+ " ConfigWriter.Update" % type(target))
+ if not test:
+ raise errors.ConfigurationError, ("Configuration updated since object"
+ " has been read or unknown object")
+ self._WriteConfig()
--- /dev/null
+#!/usr/bin/python
+#
+
+# Copyright (C) 2006, 2007 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+"""Script for unittesting the config module"""
+
+
+import unittest
+import os
+import time
+import tempfile
+import os.path
+import socket
+
+from ganeti import errors
+from ganeti import constants
+from ganeti import config
+from ganeti import objects
+
+
+class TestConfigRunner(unittest.TestCase):
+ """Testing case for HooksRunner"""
+ def setUp(self):
+ fd, self.cfg_file = tempfile.mkstemp()
+ os.close(fd)
+
+ def tearDown(self):
+ try:
+ os.unlink(self.cfg_file)
+ except OSError:
+ pass
+
+ def _get_object(self):
+ """Returns a instance of ConfigWriter"""
+ cfg = config.ConfigWriter(cfg_file=self.cfg_file, offline=True)
+ return cfg
+
+ def _init_cluster(self, cfg):
+ """Initializes the cfg object"""
+ cfg.InitConfig(socket.gethostname(), '127.0.0.1', None, '', 'aa:00:00',
+ 'xenvg', constants.DEFAULT_BRIDGE)
+
+ def _create_instance(self):
+ """Create and return an instance object"""
+ inst = objects.Instance(name="test.example.com", disks=[],
+ disk_template=constants.DT_DISKLESS)
+ return inst
+
+ def testEmpty(self):
+ """Test instantiate config object"""
+ self._get_object()
+
+ def testInit(self):
+ """Test initialize the config file"""
+ cfg = self._get_object()
+ self._init_cluster(cfg)
+ self.failUnlessEqual(1, len(cfg.GetNodeList()))
+ self.failUnlessEqual(0, len(cfg.GetInstanceList()))
+
+ def testUpdateCluster(self):
+ """Test updates on the cluster object"""
+ cfg = self._get_object()
+ # construct a fake cluster object
+ fake_cl = objects.Cluster()
+ # fail if we didn't read the config
+ self.failUnlessRaises(errors.ProgrammerError, cfg.Update, fake_cl)
+
+ self._init_cluster(cfg)
+ cl = cfg.GetClusterInfo()
+ # first pass, must not fail
+ cfg.Update(cl)
+ # second pass, also must not fail (after the config has been written)
+ cfg.Update(cl)
+ # but the fake_cl update should still fail
+ self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_cl)
+
+ def testUpdateNode(self):
+ """Test updates on one node object"""
+ cfg = self._get_object()
+ # construct a fake node
+ fake_node = objects.Node()
+ # fail if we didn't read the config
+ self.failUnlessRaises(errors.ProgrammerError, cfg.Update, fake_node)
+
+ self._init_cluster(cfg)
+ node = cfg.GetNodeInfo(cfg.GetNodeList()[0])
+ # first pass, must not fail
+ cfg.Update(node)
+ # second pass, also must not fail (after the config has been written)
+ cfg.Update(node)
+ # but the fake_node update should still fail
+ self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_node)
+
+ def testUpdateInstance(self):
+ """Test updates on one instance object"""
+ cfg = self._get_object()
+ # construct a fake instance
+ inst = self._create_instance()
+ fake_instance = objects.Instance()
+ # fail if we didn't read the config
+ self.failUnlessRaises(errors.ProgrammerError, cfg.Update, fake_instance)
+
+ self._init_cluster(cfg)
+ cfg.AddInstance(inst)
+ instance = cfg.GetInstanceInfo(cfg.GetInstanceList()[0])
+ # first pass, must not fail
+ cfg.Update(instance)
+ # second pass, also must not fail (after the config has been written)
+ cfg.Update(instance)
+ # but the fake_instance update should still fail
+ self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance)
+
+
+if __name__ == '__main__':
+ unittest.main()