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 This code handles only the types supported by simplejson. As an example, "set"
25 is a "list". Old Pickle based configurations files are converted to JSON during
39 from ganeti import utils
40 from ganeti.cli import AskUser, FORCE_OPT
47 class Error(Exception):
48 """Generic exception"""
52 # {{{ Support for old Pickle files
53 class UpgradeDict(dict):
54 """Base class for internal config classes.
57 def __setstate__(self, state):
60 def __getstate__(self):
64 def FindGlobal(module, name):
65 """Wraps Ganeti config classes to internal ones.
67 This function may only return types supported by simplejson.
70 if module == "ganeti.objects":
72 elif module == "__builtin__" and name == "set":
75 return getattr(sys.modules[module], name)
78 def ReadPickleFile(f):
79 """Reads an old Pickle configuration.
84 loader = cPickle.Unpickler(f)
85 loader.find_global = FindGlobal
90 """Checks whether a file is using the Pickle format.
95 return not re.match('^\s*\{', magic)
97 f.seek(-len(magic), 1)
102 """Reads a JSON file.
105 return simplejson.load(f)
108 def ReadConfig(path):
109 """Reads configuration file.
115 return ReadPickleFile(f)
117 return ReadJsonFile(f)
122 def WriteConfig(path, data):
123 """Writes the configuration file.
126 if not options.dry_run:
127 utils.CreateBackup(path)
129 (fd, name) = tempfile.mkstemp(dir=os.path.dirname(path))
130 f = os.fdopen(fd, 'w')
133 simplejson.dump(data, f)
138 os.rename(name, path)
146 def UpdateFromVersion2To3(cfg):
147 """Updates the configuration from version 2 to 3.
150 if cfg['cluster']['config_version'] != 2:
154 if 'tcpudp_port_pool' not in cfg['cluster']:
155 cfg['cluster']['tcpudp_port_pool'] = []
157 # Add bridge settings
158 if 'default_bridge' not in cfg['cluster']:
159 cfg['cluster']['default_bridge'] = 'xen-br0'
160 for inst in cfg['instances'].values():
161 for nic in inst['nics']:
162 if 'bridge' not in nic:
165 cfg['cluster']['config_version'] = 3
169 if __name__ == "__main__":
170 program = os.path.basename(sys.argv[0])
173 parser = optparse.OptionParser()
174 parser.add_option('--dry-run', dest='dry_run',
176 help="Try to do the conversion, but don't write"
178 parser.add_option(FORCE_OPT)
179 parser.add_option('--verbose', dest='verbose',
181 help="Verbose output")
182 (options, args) = parser.parse_args()
188 raise Error("Configuration file not specified")
190 if not options.force:
191 usertext = ("%s MUST run on the master node. Is this the master"
193 if not AskUser(usertext):
196 config = ReadConfig(cfg_file)
200 print "Before upgrade:"
201 pprint.pprint(config)
204 UpdateFromVersion2To3(config)
207 print "After upgrade:"
208 pprint.pprint(config)
211 WriteConfig(cfg_file, config)
213 print "The configuration file has been updated successfully. Please run"
214 print " gnt-cluster copyfile %s" % cfg_file
217 # vim: set foldmethod=marker :