4 # Copyright (C) 2007 Google Inc.
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.
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.
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
22 """Tool to upgrade the configuration file.
24 The upgrade is done by unpickling the configuration file into custom classes
25 derivating from dict. We then update the configuration by modifying these
26 dicts. To save the configuration, it's pickled into a buffer and unpickled
27 again using the Ganeti objects before being finally pickled into a file.
29 Not using the custom classes wouldn't allow us to rename or remove attributes
30 between versions without loosing their values.
41 from cStringIO import StringIO
43 from ganeti import objects
45 class Error(Exception):
46 """Generic exception"""
50 def _BaseFindGlobal(module, name):
51 """Helper function for the other FindGlobal functions.
54 return getattr(sys.modules[module], name)
57 # Internal config representation
58 class UpgradeDict(dict):
59 """Base class for internal config classes.
62 def __setstate__(self, state):
65 def __getstate__(self):
69 class UpgradeConfigData(UpgradeDict): pass
70 class UpgradeCluster(UpgradeDict): pass
71 class UpgradeNode(UpgradeDict): pass
72 class UpgradeInstance(UpgradeDict): pass
73 class UpgradeDisk(UpgradeDict): pass
74 class UpgradeNIC(UpgradeDict): pass
75 class UpgradeOS(UpgradeDict): pass
79 objects.ConfigData: UpgradeConfigData,
80 objects.Cluster: UpgradeCluster,
81 objects.Node: UpgradeNode,
82 objects.Instance: UpgradeInstance,
83 objects.Disk: UpgradeDisk,
84 objects.NIC: UpgradeNIC,
85 objects.OS: UpgradeOS,
91 for key, value in _ClassMap.iteritems():
92 WriteMapping[value.__name__] = key
93 ReadMapping[key.__name__] = value
97 def _ReadFindGlobal(module, name):
98 """Wraps Ganeti config classes to internal ones.
101 if module == "ganeti.objects" and name in ReadMapping:
102 return ReadMapping[name]
104 return _BaseFindGlobal(module, name)
107 def ReadConfig(path):
108 """Reads configuration file.
113 loader = cPickle.Unpickler(f)
114 loader.find_global = _ReadFindGlobal
123 def _WriteFindGlobal(module, name):
124 """Maps our internal config classes to Ganeti's.
127 if module == "__main__" and name in WriteMapping:
128 return WriteMapping[name]
130 return _BaseFindGlobal(module, name)
133 def WriteConfig(path, data, dry_run):
134 """Writes the configuration file.
139 # Write intermediate representation
140 dumper = cPickle.Pickler(buf, cPickle.HIGHEST_PROTOCOL)
144 # Convert back to Ganeti objects
146 loader = cPickle.Unpickler(buf)
147 loader.find_global = _WriteFindGlobal
151 (fd, name) = tempfile.mkstemp(dir=os.path.dirname(path))
152 f = os.fdopen(fd, 'w')
155 dumper = cPickle.Pickler(f, cPickle.HIGHEST_PROTOCOL)
161 os.rename(name, path)
169 def UpdateFromVersion2To3(cfg):
170 """Updates the configuration from version 2 to 3.
173 if cfg['cluster']['config_version'] != 2:
177 if 'tcpudp_port_pool' not in cfg['cluster']:
178 cfg['cluster']['tcpudp_port_pool'] = set()
180 # Add bridge settings
181 if 'default_bridge' not in cfg['cluster']:
182 cfg['cluster']['default_bridge'] = 'xen-br0'
183 for inst in cfg['instances'].values():
184 for nic in inst['nics']:
185 if 'bridge' not in nic:
188 cfg['cluster']['config_version'] = 3
192 if __name__ == "__main__":
194 parser = optparse.OptionParser()
195 parser.add_option('--dry-run', dest='dry_run',
197 help="Try to do the conversion, but don't write "
199 parser.add_option('--verbose', dest='verbose',
201 help="Verbose output")
202 (options, args) = parser.parse_args()
208 raise Error, ("Configuration file not specified")
210 config = ReadConfig(cfg_file)
212 UpdateFromVersion2To3(config)
216 pprint.pprint(config)
218 WriteConfig(cfg_file, config, options.dry_run)