Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade @ 6e06b36c

History | View | Annotate | Download (4.6 kB)

1 0006af7d Michael Hanselmann
#!/usr/bin/python
2 0006af7d Michael Hanselmann
#
3 0006af7d Michael Hanselmann
4 0006af7d Michael Hanselmann
# Copyright (C) 2007 Google Inc.
5 0006af7d Michael Hanselmann
#
6 0006af7d Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 0006af7d Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 0006af7d Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 0006af7d Michael Hanselmann
# (at your option) any later version.
10 0006af7d Michael Hanselmann
#
11 0006af7d Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 0006af7d Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 0006af7d Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 0006af7d Michael Hanselmann
# General Public License for more details.
15 0006af7d Michael Hanselmann
#
16 0006af7d Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 0006af7d Michael Hanselmann
# along with this program; if not, write to the Free Software
18 0006af7d Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 0006af7d Michael Hanselmann
# 02110-1301, USA.
20 0006af7d Michael Hanselmann
21 0006af7d Michael Hanselmann
22 0006af7d Michael Hanselmann
"""Tool to upgrade the configuration file.
23 0006af7d Michael Hanselmann
24 319856a9 Michael Hanselmann
This code handles only the types supported by simplejson. As an example, "set"
25 319856a9 Michael Hanselmann
is a "list". Old Pickle based configurations files are converted to JSON during
26 319856a9 Michael Hanselmann
the process.
27 0006af7d Michael Hanselmann
28 0006af7d Michael Hanselmann
"""
29 0006af7d Michael Hanselmann
30 0006af7d Michael Hanselmann
31 0006af7d Michael Hanselmann
import os
32 0006af7d Michael Hanselmann
import os.path
33 0006af7d Michael Hanselmann
import sys
34 319856a9 Michael Hanselmann
import re
35 0006af7d Michael Hanselmann
import optparse
36 0006af7d Michael Hanselmann
import tempfile
37 319856a9 Michael Hanselmann
import simplejson
38 0006af7d Michael Hanselmann
39 319856a9 Michael Hanselmann
from ganeti import utils
40 319856a9 Michael Hanselmann
from ganeti.cli import AskUser, FORCE_OPT
41 0006af7d Michael Hanselmann
42 0006af7d Michael Hanselmann
43 319856a9 Michael Hanselmann
options = None
44 319856a9 Michael Hanselmann
args = None
45 0006af7d Michael Hanselmann
46 0006af7d Michael Hanselmann
47 319856a9 Michael Hanselmann
class Error(Exception):
48 319856a9 Michael Hanselmann
  """Generic exception"""
49 319856a9 Michael Hanselmann
  pass
50 0006af7d Michael Hanselmann
51 0006af7d Michael Hanselmann
52 319856a9 Michael Hanselmann
# {{{ Support for old Pickle files
53 0006af7d Michael Hanselmann
class UpgradeDict(dict):
54 0006af7d Michael Hanselmann
  """Base class for internal config classes.
55 0006af7d Michael Hanselmann
56 0006af7d Michael Hanselmann
  """
57 0006af7d Michael Hanselmann
  def __setstate__(self, state):
58 0006af7d Michael Hanselmann
    self.update(state)
59 0006af7d Michael Hanselmann
60 0006af7d Michael Hanselmann
  def __getstate__(self):
61 0006af7d Michael Hanselmann
    return self.copy()
62 0006af7d Michael Hanselmann
63 0006af7d Michael Hanselmann
64 319856a9 Michael Hanselmann
def FindGlobal(module, name):
65 319856a9 Michael Hanselmann
  """Wraps Ganeti config classes to internal ones.
66 0006af7d Michael Hanselmann
67 319856a9 Michael Hanselmann
  This function may only return types supported by simplejson.
68 0006af7d Michael Hanselmann
69 319856a9 Michael Hanselmann
  """
70 319856a9 Michael Hanselmann
  if module == "ganeti.objects":
71 319856a9 Michael Hanselmann
    return UpgradeDict
72 319856a9 Michael Hanselmann
  elif module == "__builtin__" and name == "set":
73 319856a9 Michael Hanselmann
    return list
74 0006af7d Michael Hanselmann
75 319856a9 Michael Hanselmann
  return getattr(sys.modules[module], name)
76 0006af7d Michael Hanselmann
77 0006af7d Michael Hanselmann
78 319856a9 Michael Hanselmann
def ReadPickleFile(f):
79 319856a9 Michael Hanselmann
  """Reads an old Pickle configuration.
80 0006af7d Michael Hanselmann
81 0006af7d Michael Hanselmann
  """
82 319856a9 Michael Hanselmann
  import cPickle
83 0006af7d Michael Hanselmann
84 319856a9 Michael Hanselmann
  loader = cPickle.Unpickler(f)
85 319856a9 Michael Hanselmann
  loader.find_global = FindGlobal
86 319856a9 Michael Hanselmann
  return loader.load()
87 0006af7d Michael Hanselmann
88 0006af7d Michael Hanselmann
89 319856a9 Michael Hanselmann
def IsPickleFile(f):
90 319856a9 Michael Hanselmann
  """Checks whether a file is using the Pickle format.
91 0006af7d Michael Hanselmann
92 0006af7d Michael Hanselmann
  """
93 319856a9 Michael Hanselmann
  magic = f.read(128)
94 0006af7d Michael Hanselmann
  try:
95 319856a9 Michael Hanselmann
    return not re.match('^\s*\{', magic)
96 0006af7d Michael Hanselmann
  finally:
97 319856a9 Michael Hanselmann
    f.seek(-len(magic), 1)
98 319856a9 Michael Hanselmann
# }}}
99 0006af7d Michael Hanselmann
100 0006af7d Michael Hanselmann
101 319856a9 Michael Hanselmann
def ReadJsonFile(f):
102 319856a9 Michael Hanselmann
  """Reads a JSON file.
103 0006af7d Michael Hanselmann
104 0006af7d Michael Hanselmann
  """
105 319856a9 Michael Hanselmann
  return simplejson.load(f)
106 0006af7d Michael Hanselmann
107 0006af7d Michael Hanselmann
108 319856a9 Michael Hanselmann
def ReadConfig(path):
109 319856a9 Michael Hanselmann
  """Reads configuration file.
110 0006af7d Michael Hanselmann
111 0006af7d Michael Hanselmann
  """
112 319856a9 Michael Hanselmann
  f = open(path, 'r')
113 319856a9 Michael Hanselmann
  try:
114 319856a9 Michael Hanselmann
    if IsPickleFile(f):
115 319856a9 Michael Hanselmann
      return ReadPickleFile(f)
116 319856a9 Michael Hanselmann
    else:
117 319856a9 Michael Hanselmann
      return ReadJsonFile(f)
118 319856a9 Michael Hanselmann
  finally:
119 319856a9 Michael Hanselmann
    f.close()
120 0006af7d Michael Hanselmann
121 0006af7d Michael Hanselmann
122 319856a9 Michael Hanselmann
def WriteConfig(path, data):
123 319856a9 Michael Hanselmann
  """Writes the configuration file.
124 319856a9 Michael Hanselmann
125 319856a9 Michael Hanselmann
  """
126 319856a9 Michael Hanselmann
  if not options.dry_run:
127 319856a9 Michael Hanselmann
    utils.CreateBackup(path)
128 0006af7d Michael Hanselmann
129 0006af7d Michael Hanselmann
  (fd, name) = tempfile.mkstemp(dir=os.path.dirname(path))
130 0006af7d Michael Hanselmann
  f = os.fdopen(fd, 'w')
131 0006af7d Michael Hanselmann
  try:
132 0006af7d Michael Hanselmann
    try:
133 319856a9 Michael Hanselmann
      simplejson.dump(data, f)
134 0006af7d Michael Hanselmann
      f.flush()
135 319856a9 Michael Hanselmann
      if options.dry_run:
136 60edf71e Michael Hanselmann
        os.unlink(name)
137 60edf71e Michael Hanselmann
      else:
138 60edf71e Michael Hanselmann
        os.rename(name, path)
139 0006af7d Michael Hanselmann
    except:
140 0006af7d Michael Hanselmann
      os.unlink(name)
141 0006af7d Michael Hanselmann
      raise
142 0006af7d Michael Hanselmann
  finally:
143 0006af7d Michael Hanselmann
    f.close()
144 0006af7d Michael Hanselmann
145 0006af7d Michael Hanselmann
146 0006af7d Michael Hanselmann
def UpdateFromVersion2To3(cfg):
147 0006af7d Michael Hanselmann
  """Updates the configuration from version 2 to 3.
148 0006af7d Michael Hanselmann
149 0006af7d Michael Hanselmann
  """
150 0006af7d Michael Hanselmann
  if cfg['cluster']['config_version'] != 2:
151 0006af7d Michael Hanselmann
    return
152 0006af7d Michael Hanselmann
153 0006af7d Michael Hanselmann
  # Add port pool
154 0006af7d Michael Hanselmann
  if 'tcpudp_port_pool' not in cfg['cluster']:
155 319856a9 Michael Hanselmann
    cfg['cluster']['tcpudp_port_pool'] = []
156 0006af7d Michael Hanselmann
157 0006af7d Michael Hanselmann
  # Add bridge settings
158 0006af7d Michael Hanselmann
  if 'default_bridge' not in cfg['cluster']:
159 0006af7d Michael Hanselmann
    cfg['cluster']['default_bridge'] = 'xen-br0'
160 0006af7d Michael Hanselmann
  for inst in cfg['instances'].values():
161 0006af7d Michael Hanselmann
    for nic in inst['nics']:
162 0006af7d Michael Hanselmann
      if 'bridge' not in nic:
163 0006af7d Michael Hanselmann
        nic['bridge'] = None
164 0006af7d Michael Hanselmann
165 0006af7d Michael Hanselmann
  cfg['cluster']['config_version'] = 3
166 0006af7d Michael Hanselmann
167 0006af7d Michael Hanselmann
168 0006af7d Michael Hanselmann
# Main program
169 0006af7d Michael Hanselmann
if __name__ == "__main__":
170 319856a9 Michael Hanselmann
  program = os.path.basename(sys.argv[0])
171 319856a9 Michael Hanselmann
172 0006af7d Michael Hanselmann
  # Option parsing
173 0006af7d Michael Hanselmann
  parser = optparse.OptionParser()
174 60edf71e Michael Hanselmann
  parser.add_option('--dry-run', dest='dry_run',
175 60edf71e Michael Hanselmann
                    action="store_true",
176 60edf71e Michael Hanselmann
                    help="Try to do the conversion, but don't write "
177 60edf71e Michael Hanselmann
                      "output file")
178 319856a9 Michael Hanselmann
  parser.add_option(FORCE_OPT)
179 0006af7d Michael Hanselmann
  parser.add_option('--verbose', dest='verbose',
180 0006af7d Michael Hanselmann
                    action="store_true",
181 0006af7d Michael Hanselmann
                    help="Verbose output")
182 0006af7d Michael Hanselmann
  (options, args) = parser.parse_args()
183 0006af7d Michael Hanselmann
184 0006af7d Michael Hanselmann
  # Option checking
185 0006af7d Michael Hanselmann
  if args:
186 0006af7d Michael Hanselmann
    cfg_file = args[0]
187 0006af7d Michael Hanselmann
  else:
188 3ecf6786 Iustin Pop
    raise Error("Configuration file not specified")
189 0006af7d Michael Hanselmann
190 319856a9 Michael Hanselmann
  if not options.force:
191 319856a9 Michael Hanselmann
    usertext = ("%s MUST run on the master node. Is this the master "
192 319856a9 Michael Hanselmann
                "node?" % program)
193 319856a9 Michael Hanselmann
    if not AskUser(usertext):
194 319856a9 Michael Hanselmann
      sys.exit(1)
195 319856a9 Michael Hanselmann
196 0006af7d Michael Hanselmann
  config = ReadConfig(cfg_file)
197 0006af7d Michael Hanselmann
198 319856a9 Michael Hanselmann
  if options.verbose:
199 319856a9 Michael Hanselmann
    import pprint
200 319856a9 Michael Hanselmann
    print "Before upgrade:"
201 319856a9 Michael Hanselmann
    pprint.pprint(config)
202 319856a9 Michael Hanselmann
    print
203 319856a9 Michael Hanselmann
204 0006af7d Michael Hanselmann
  UpdateFromVersion2To3(config)
205 0006af7d Michael Hanselmann
206 0006af7d Michael Hanselmann
  if options.verbose:
207 319856a9 Michael Hanselmann
    print "After upgrade:"
208 0006af7d Michael Hanselmann
    pprint.pprint(config)
209 319856a9 Michael Hanselmann
    print
210 319856a9 Michael Hanselmann
211 319856a9 Michael Hanselmann
  WriteConfig(cfg_file, config)
212 319856a9 Michael Hanselmann
213 319856a9 Michael Hanselmann
  print "The configuration file has been updated successfully. Please run"
214 319856a9 Michael Hanselmann
  print "  gnt-cluster copyfile %s" % cfg_file
215 319856a9 Michael Hanselmann
  print "now."
216 0006af7d Michael Hanselmann
217 319856a9 Michael Hanselmann
# vim: set foldmethod=marker :