Revision 45f62156
b/lib/config.py | ||
---|---|---|
34 | 34 |
# pylint: disable=R0904 |
35 | 35 |
# R0904: Too many public methods |
36 | 36 |
|
37 |
import copy |
|
37 | 38 |
import os |
38 | 39 |
import random |
39 | 40 |
import logging |
... | ... | |
2033 | 2034 |
(data.cluster.master_node, self._my_hostname)) |
2034 | 2035 |
raise errors.ConfigurationError(msg) |
2035 | 2036 |
|
2036 |
# Upgrade configuration if needed |
|
2037 |
data.UpgradeConfig() |
|
2038 |
|
|
2039 | 2037 |
self._config_data = data |
2040 | 2038 |
# reset the last serial as -1 so that the next write will cause |
2041 | 2039 |
# ssconf update |
2042 | 2040 |
self._last_cluster_serial = -1 |
2043 | 2041 |
|
2044 |
# And finally run our (custom) config upgrade sequence
|
|
2042 |
# Upgrade configuration if needed
|
|
2045 | 2043 |
self._UpgradeConfig() |
2046 | 2044 |
|
2047 | 2045 |
self._cfg_id = utils.GetFileID(path=self._cfg_file) |
2048 | 2046 |
|
2049 | 2047 |
def _UpgradeConfig(self): |
2050 |
"""Run upgrade steps that cannot be done purely in the objects.
|
|
2048 |
"""Run any upgrade steps.
|
|
2051 | 2049 |
|
2052 |
This is because some data elements need uniqueness across the |
|
2053 |
whole configuration, etc. |
|
2050 |
This method performs both in-object upgrades and also update some data |
|
2051 |
elements that need uniqueness across the whole configuration or interact |
|
2052 |
with other objects. |
|
2054 | 2053 |
|
2055 | 2054 |
@warning: this function will call L{_WriteConfig()}, but also |
2056 | 2055 |
L{DropECReservations} so it needs to be called only from a |
... | ... | |
2059 | 2058 |
created first, to avoid causing deadlock. |
2060 | 2059 |
|
2061 | 2060 |
""" |
2062 |
modified = False |
|
2061 |
# Keep a copy of the persistent part of _config_data to check for changes |
|
2062 |
# Serialization doesn't guarantee order in dictionaries |
|
2063 |
oldconf = copy.deepcopy(self._config_data.ToDict()) |
|
2064 |
|
|
2065 |
# In-object upgrades |
|
2066 |
self._config_data.UpgradeConfig() |
|
2067 |
|
|
2063 | 2068 |
for item in self._AllUUIDObjects(): |
2064 | 2069 |
if item.uuid is None: |
2065 | 2070 |
item.uuid = self._GenerateUniqueID(_UPGRADE_CONFIG_JID) |
2066 |
modified = True |
|
2067 | 2071 |
if not self._config_data.nodegroups: |
2068 | 2072 |
default_nodegroup_name = constants.INITIAL_NODE_GROUP_NAME |
2069 | 2073 |
default_nodegroup = objects.NodeGroup(name=default_nodegroup_name, |
2070 | 2074 |
members=[]) |
2071 | 2075 |
self._UnlockedAddNodeGroup(default_nodegroup, _UPGRADE_CONFIG_JID, True) |
2072 |
modified = True |
|
2073 | 2076 |
for node in self._config_data.nodes.values(): |
2074 | 2077 |
if not node.group: |
2075 | 2078 |
node.group = self.LookupNodeGroup(None) |
2076 |
modified = True |
|
2077 | 2079 |
# This is technically *not* an upgrade, but needs to be done both when |
2078 | 2080 |
# nodegroups are being added, and upon normally loading the config, |
2079 | 2081 |
# because the members list of a node group is discarded upon |
2080 | 2082 |
# serializing/deserializing the object. |
2081 | 2083 |
self._UnlockedAddNodeToGroup(node.name, node.group) |
2084 |
|
|
2085 |
modified = (oldconf != self._config_data.ToDict()) |
|
2082 | 2086 |
if modified: |
2083 | 2087 |
self._WriteConfig() |
2084 | 2088 |
# This is ok even if it acquires the internal lock, as _UpgradeConfig is |
b/test/py/ganeti.config_unittest.py | ||
---|---|---|
174 | 174 |
self.failUnlessRaises(errors.ConfigurationError, cfg.Update, fake_instance, |
175 | 175 |
None) |
176 | 176 |
|
177 |
def testUpgradeSave(self): |
|
178 |
"""Test that any modification done during upgrading is saved back""" |
|
179 |
cfg = self._get_object() |
|
180 |
|
|
181 |
# Remove an element, run upgrade, and check if the element is |
|
182 |
# back and the file upgraded |
|
183 |
node = cfg.GetNodeInfo(cfg.GetNodeList()[0]) |
|
184 |
# For a ConfigObject, None is the same as a missing field |
|
185 |
node.ndparams = None |
|
186 |
oldsaved = utils.ReadFile(self.cfg_file) |
|
187 |
cfg._UpgradeConfig() |
|
188 |
self.assertTrue(node.ndparams is not None) |
|
189 |
newsaved = utils.ReadFile(self.cfg_file) |
|
190 |
# We rely on the fact that at least the serial number changes |
|
191 |
self.assertNotEqual(oldsaved, newsaved) |
|
192 |
|
|
193 |
# Add something that should not be there this time |
|
194 |
key = list(constants.NDC_GLOBALS)[0] |
|
195 |
node.ndparams[key] = constants.NDC_DEFAULTS[key] |
|
196 |
cfg._WriteConfig(None) |
|
197 |
oldsaved = utils.ReadFile(self.cfg_file) |
|
198 |
cfg._UpgradeConfig() |
|
199 |
self.assertTrue(node.ndparams.get(key) is None) |
|
200 |
newsaved = utils.ReadFile(self.cfg_file) |
|
201 |
self.assertNotEqual(oldsaved, newsaved) |
|
202 |
|
|
203 |
# Do the upgrade again, this time there should be no update |
|
204 |
oldsaved = newsaved |
|
205 |
cfg._UpgradeConfig() |
|
206 |
newsaved = utils.ReadFile(self.cfg_file) |
|
207 |
self.assertEqual(oldsaved, newsaved) |
|
208 |
|
|
209 |
# Reload the configuration again: it shouldn't change the file |
|
210 |
oldsaved = newsaved |
|
211 |
self._get_object() |
|
212 |
newsaved = utils.ReadFile(self.cfg_file) |
|
213 |
self.assertEqual(oldsaved, newsaved) |
|
214 |
|
|
177 | 215 |
def testNICParameterSyntaxCheck(self): |
178 | 216 |
"""Test the NIC's CheckParameterSyntax function""" |
179 | 217 |
mode = constants.NIC_MODE |
Also available in: Unified diff