Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade @ 6b7d5878

History | View | Annotate | Download (6 kB)

1 0006af7d Michael Hanselmann
#!/usr/bin/python
2 0006af7d Michael Hanselmann
#
3 0006af7d Michael Hanselmann
4 a421fdeb Iustin Pop
# Copyright (C) 2007, 2008, 2009 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 a421fdeb Iustin Pop
This code handles only the types supported by simplejson. As an
25 a421fdeb Iustin Pop
example, 'set' is a 'list'.
26 0006af7d Michael Hanselmann
27 0006af7d Michael Hanselmann
"""
28 0006af7d Michael Hanselmann
29 0006af7d Michael Hanselmann
30 0006af7d Michael Hanselmann
import os
31 0006af7d Michael Hanselmann
import os.path
32 0006af7d Michael Hanselmann
import sys
33 0006af7d Michael Hanselmann
import optparse
34 eda37a5a Michael Hanselmann
import logging
35 0006af7d Michael Hanselmann
36 95e4a814 Michael Hanselmann
from ganeti import constants
37 95e4a814 Michael Hanselmann
from ganeti import serializer
38 319856a9 Michael Hanselmann
from ganeti import utils
39 f97c7901 Michael Hanselmann
from ganeti import cli
40 a421fdeb Iustin Pop
from ganeti import bootstrap
41 ac4d25b6 Iustin Pop
from ganeti import config
42 0006af7d Michael Hanselmann
43 0006af7d Michael Hanselmann
44 319856a9 Michael Hanselmann
options = None
45 319856a9 Michael Hanselmann
args = None
46 0006af7d Michael Hanselmann
47 ac4d25b6 Iustin Pop
# Dictionary with instance old keys, and new hypervisor keys
48 ac4d25b6 Iustin Pop
INST_HV_CHG = {
49 ac4d25b6 Iustin Pop
  'hvm_pae': constants.HV_PAE,
50 ac4d25b6 Iustin Pop
  'vnc_bind_address': constants.HV_VNC_BIND_ADDRESS,
51 ac4d25b6 Iustin Pop
  'initrd_path': constants.HV_INITRD_PATH,
52 ac4d25b6 Iustin Pop
  'hvm_nic_type': constants.HV_NIC_TYPE,
53 ac4d25b6 Iustin Pop
  'kernel_path': constants.HV_KERNEL_PATH,
54 ac4d25b6 Iustin Pop
  'hvm_acpi': constants.HV_ACPI,
55 ac4d25b6 Iustin Pop
  'hvm_cdrom_image_path': constants.HV_CDROM_IMAGE_PATH,
56 ac4d25b6 Iustin Pop
  'hvm_boot_order': constants.HV_BOOT_ORDER,
57 ac4d25b6 Iustin Pop
  'hvm_disk_type': constants.HV_DISK_TYPE,
58 ac4d25b6 Iustin Pop
  }
59 ac4d25b6 Iustin Pop
60 ac4d25b6 Iustin Pop
# Instance beparams changes
61 ac4d25b6 Iustin Pop
INST_BE_CHG = {
62 ac4d25b6 Iustin Pop
  'vcpus': constants.BE_VCPUS,
63 ac4d25b6 Iustin Pop
  'memory': constants.BE_MEMORY,
64 ac4d25b6 Iustin Pop
  'auto_balance': constants.BE_AUTO_BALANCE,
65 ac4d25b6 Iustin Pop
  }
66 0006af7d Michael Hanselmann
67 6f285030 Iustin Pop
# Field names
68 6f285030 Iustin Pop
F_SERIAL = 'serial_no'
69 6f285030 Iustin Pop
70 6f285030 Iustin Pop
71 319856a9 Michael Hanselmann
class Error(Exception):
72 319856a9 Michael Hanselmann
  """Generic exception"""
73 319856a9 Michael Hanselmann
  pass
74 0006af7d Michael Hanselmann
75 0006af7d Michael Hanselmann
76 eda37a5a Michael Hanselmann
def SetupLogging():
77 eda37a5a Michael Hanselmann
  """Configures the logging module.
78 eda37a5a Michael Hanselmann
79 eda37a5a Michael Hanselmann
  """
80 eda37a5a Michael Hanselmann
  formatter = logging.Formatter("%(asctime)s: %(message)s")
81 eda37a5a Michael Hanselmann
82 eda37a5a Michael Hanselmann
  stderr_handler = logging.StreamHandler()
83 eda37a5a Michael Hanselmann
  stderr_handler.setFormatter(formatter)
84 eda37a5a Michael Hanselmann
  if options.debug:
85 eda37a5a Michael Hanselmann
    stderr_handler.setLevel(logging.NOTSET)
86 eda37a5a Michael Hanselmann
  elif options.verbose:
87 eda37a5a Michael Hanselmann
    stderr_handler.setLevel(logging.INFO)
88 eda37a5a Michael Hanselmann
  else:
89 eda37a5a Michael Hanselmann
    stderr_handler.setLevel(logging.CRITICAL)
90 eda37a5a Michael Hanselmann
91 eda37a5a Michael Hanselmann
  root_logger = logging.getLogger("")
92 eda37a5a Michael Hanselmann
  root_logger.setLevel(logging.NOTSET)
93 eda37a5a Michael Hanselmann
  root_logger.addHandler(stderr_handler)
94 eda37a5a Michael Hanselmann
95 eda37a5a Michael Hanselmann
96 6d691282 Michael Hanselmann
def main():
97 6d691282 Michael Hanselmann
  """Main program.
98 6d691282 Michael Hanselmann
99 6d691282 Michael Hanselmann
  """
100 7260cfbe Iustin Pop
  global options, args # pylint: disable-msg=W0603
101 6d691282 Michael Hanselmann
102 319856a9 Michael Hanselmann
  program = os.path.basename(sys.argv[0])
103 319856a9 Michael Hanselmann
104 0006af7d Michael Hanselmann
  # Option parsing
105 95e4a814 Michael Hanselmann
  parser = optparse.OptionParser(usage="%prog [--debug|--verbose] [--force]")
106 60edf71e Michael Hanselmann
  parser.add_option('--dry-run', dest='dry_run',
107 60edf71e Michael Hanselmann
                    action="store_true",
108 f4bc1f2c Michael Hanselmann
                    help="Try to do the conversion, but don't write"
109 f4bc1f2c Michael Hanselmann
                         " output file")
110 f97c7901 Michael Hanselmann
  parser.add_option(cli.FORCE_OPT)
111 eda37a5a Michael Hanselmann
  parser.add_option(cli.DEBUG_OPT)
112 9cdb9578 Iustin Pop
  parser.add_option(cli.VERBOSE_OPT)
113 ac4d25b6 Iustin Pop
  parser.add_option('--path', help="Convert configuration in this"
114 ac4d25b6 Iustin Pop
                    " directory instead of '%s'" % constants.DATA_DIR,
115 ac4d25b6 Iustin Pop
                    default=constants.DATA_DIR, dest="data_dir")
116 0006af7d Michael Hanselmann
  (options, args) = parser.parse_args()
117 0006af7d Michael Hanselmann
118 ac4d25b6 Iustin Pop
  # We need to keep filenames locally because they might be renamed between
119 ac4d25b6 Iustin Pop
  # versions.
120 ac4d25b6 Iustin Pop
  options.CONFIG_DATA_PATH = options.data_dir + "/config.data"
121 ac4d25b6 Iustin Pop
  options.SERVER_PEM_PATH = options.data_dir + "/server.pem"
122 ac4d25b6 Iustin Pop
  options.KNOWN_HOSTS_PATH = options.data_dir + "/known_hosts"
123 ac4d25b6 Iustin Pop
  options.RAPI_CERT_FILE = options.data_dir + "/rapi.pem"
124 6b7d5878 Michael Hanselmann
  options.CONFD_HMAC_KEY = options.data_dir + "/hmac.key"
125 ac4d25b6 Iustin Pop
126 eda37a5a Michael Hanselmann
  SetupLogging()
127 eda37a5a Michael Hanselmann
128 0006af7d Michael Hanselmann
  # Option checking
129 0006af7d Michael Hanselmann
  if args:
130 95e4a814 Michael Hanselmann
    raise Error("No arguments expected")
131 0006af7d Michael Hanselmann
132 319856a9 Michael Hanselmann
  if not options.force:
133 a421fdeb Iustin Pop
    usertext = ("%s MUST be run on the master node. Is this the master"
134 a421fdeb Iustin Pop
                " node and are ALL instances down?" % program)
135 f97c7901 Michael Hanselmann
    if not cli.AskUser(usertext):
136 319856a9 Michael Hanselmann
      sys.exit(1)
137 319856a9 Michael Hanselmann
138 95e4a814 Michael Hanselmann
  # Check whether it's a Ganeti configuration directory
139 ac4d25b6 Iustin Pop
  if not (os.path.isfile(options.CONFIG_DATA_PATH) and
140 ac4d25b6 Iustin Pop
          os.path.isfile(options.SERVER_PEM_PATH) or
141 ac4d25b6 Iustin Pop
          os.path.isfile(options.KNOWN_HOSTS_PATH)):
142 95e4a814 Michael Hanselmann
    raise Error(("%s does not seem to be a known Ganeti configuration"
143 ac4d25b6 Iustin Pop
                 " directory") % options.data_dir)
144 95e4a814 Michael Hanselmann
145 11c31f5c Michael Hanselmann
  config_data = serializer.LoadJson(utils.ReadFile(options.CONFIG_DATA_PATH))
146 a421fdeb Iustin Pop
147 11c31f5c Michael Hanselmann
  try:
148 11c31f5c Michael Hanselmann
    config_version = config_data["version"]
149 11c31f5c Michael Hanselmann
  except KeyError:
150 11c31f5c Michael Hanselmann
    raise Error("Unable to determine configuration version")
151 0006af7d Michael Hanselmann
152 11c31f5c Michael Hanselmann
  (config_major, config_minor, config_revision) = \
153 11c31f5c Michael Hanselmann
    constants.SplitVersion(config_version)
154 319856a9 Michael Hanselmann
155 11c31f5c Michael Hanselmann
  logging.info("Found configuration version %s (%d.%d.%d)",
156 11c31f5c Michael Hanselmann
               config_version, config_major, config_minor, config_revision)
157 319856a9 Michael Hanselmann
158 11c31f5c Michael Hanselmann
  if "config_version" in config_data["cluster"]:
159 11c31f5c Michael Hanselmann
    raise Error("Inconsistent configuration: found config_version in"
160 11c31f5c Michael Hanselmann
                " configuration file")
161 95e4a814 Michael Hanselmann
162 aeb0c953 Michael Hanselmann
  if config_major == 2 and config_minor == 0:
163 aeb0c953 Michael Hanselmann
    if config_revision != 0:
164 aeb0c953 Michael Hanselmann
      logging.warning("Config revision is not 0")
165 aeb0c953 Michael Hanselmann
166 aeb0c953 Michael Hanselmann
    config_data["version"] = constants.BuildVersion(2, 1, 0)
167 aeb0c953 Michael Hanselmann
168 11c31f5c Michael Hanselmann
  try:
169 11c31f5c Michael Hanselmann
    logging.info("Writing configuration file to %s", options.CONFIG_DATA_PATH)
170 11c31f5c Michael Hanselmann
    utils.WriteFile(file_name=options.CONFIG_DATA_PATH,
171 11c31f5c Michael Hanselmann
                    data=serializer.DumpJson(config_data),
172 11c31f5c Michael Hanselmann
                    mode=0600,
173 11c31f5c Michael Hanselmann
                    dry_run=options.dry_run,
174 11c31f5c Michael Hanselmann
                    backup=True)
175 a421fdeb Iustin Pop
176 a421fdeb Iustin Pop
    if not options.dry_run:
177 7506a7f1 Michael Hanselmann
      bootstrap.GenerateClusterCrypto(False, False, False)
178 aeb0c953 Michael Hanselmann
179 95e4a814 Michael Hanselmann
  except:
180 11c31f5c Michael Hanselmann
    logging.critical("Writing configuration failed. It is probably in an"
181 95e4a814 Michael Hanselmann
                     " inconsistent state and needs manual intervention.")
182 95e4a814 Michael Hanselmann
    raise
183 0006af7d Michael Hanselmann
184 ac4d25b6 Iustin Pop
  # test loading the config file
185 ac4d25b6 Iustin Pop
  if not options.dry_run:
186 ac4d25b6 Iustin Pop
    logging.info("Testing the new config file...")
187 ac4d25b6 Iustin Pop
    cfg = config.ConfigWriter(cfg_file=options.CONFIG_DATA_PATH,
188 ac4d25b6 Iustin Pop
                              offline=True)
189 ac4d25b6 Iustin Pop
    # if we reached this, it's all fine
190 ac4d25b6 Iustin Pop
    vrfy = cfg.VerifyConfig()
191 ac4d25b6 Iustin Pop
    if vrfy:
192 ac4d25b6 Iustin Pop
      logging.error("Errors after conversion:")
193 ac4d25b6 Iustin Pop
      for item in vrfy:
194 07b8a2b5 Iustin Pop
        logging.error(" - %s", item)
195 ac4d25b6 Iustin Pop
    del cfg
196 ac4d25b6 Iustin Pop
    logging.info("File loaded successfully")
197 ac4d25b6 Iustin Pop
198 6d691282 Michael Hanselmann
199 6d691282 Michael Hanselmann
if __name__ == "__main__":
200 6d691282 Michael Hanselmann
  main()
201 6d691282 Michael Hanselmann
202 319856a9 Michael Hanselmann
# vim: set foldmethod=marker :