Commit e00fb268 authored by Iustin Pop's avatar Iustin Pop
Browse files

Prepare for the tags implementation:

  - add an Update method on the ConfigWriter class;
  - make the AddInstance method not log disks for diskless types (helps with testing)
  - implement limited testing for the ConfigWriter with focus on the new Update method
parent c2a62a33
......@@ -297,8 +297,9 @@ class ConfigWriter:
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
......@@ -624,3 +625,30 @@ class ConfigWriter:
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()
#!/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()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment