Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade12 @ 18397489

History | View | Annotate | Download (12.1 kB)

1 b5672ea0 Iustin Pop
#!/usr/bin/python
2 b5672ea0 Iustin Pop
#
3 b5672ea0 Iustin Pop
4 b5672ea0 Iustin Pop
# Copyright (C) 2007, 2008, 2009 Google Inc.
5 b5672ea0 Iustin Pop
#
6 b5672ea0 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 b5672ea0 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 b5672ea0 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 b5672ea0 Iustin Pop
# (at your option) any later version.
10 b5672ea0 Iustin Pop
#
11 b5672ea0 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 b5672ea0 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 b5672ea0 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 b5672ea0 Iustin Pop
# General Public License for more details.
15 b5672ea0 Iustin Pop
#
16 b5672ea0 Iustin Pop
# You should have received a copy of the GNU General Public License
17 b5672ea0 Iustin Pop
# along with this program; if not, write to the Free Software
18 b5672ea0 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 b5672ea0 Iustin Pop
# 02110-1301, USA.
20 b5672ea0 Iustin Pop
21 b459a848 Andrea Spadaccini
# pylint: disable=C0103,E1103
22 b5672ea0 Iustin Pop
23 b5672ea0 Iustin Pop
# C0103: invalid name NoDefault
24 b5672ea0 Iustin Pop
# E1103: Instance of 'foor' has no 'bar' member (but some types could
25 b5672ea0 Iustin Pop
# not be inferred)
26 b5672ea0 Iustin Pop
27 b5672ea0 Iustin Pop
28 b5672ea0 Iustin Pop
"""Tool to upgrade the configuration file.
29 b5672ea0 Iustin Pop
30 b5672ea0 Iustin Pop
This code handles only the types supported by simplejson. As an
31 b5672ea0 Iustin Pop
example, 'set' is a 'list'.
32 b5672ea0 Iustin Pop
33 b5672ea0 Iustin Pop
@note: this has lots of duplicate content with C{cfgupgrade}. Ideally, it
34 b5672ea0 Iustin Pop
should be merged.
35 b5672ea0 Iustin Pop
36 b5672ea0 Iustin Pop
"""
37 b5672ea0 Iustin Pop
38 b5672ea0 Iustin Pop
39 b5672ea0 Iustin Pop
import os
40 b5672ea0 Iustin Pop
import os.path
41 b5672ea0 Iustin Pop
import sys
42 b5672ea0 Iustin Pop
import optparse
43 b5672ea0 Iustin Pop
import logging
44 b5672ea0 Iustin Pop
import errno
45 b5672ea0 Iustin Pop
46 b5672ea0 Iustin Pop
from ganeti import constants
47 b5672ea0 Iustin Pop
from ganeti import serializer
48 b5672ea0 Iustin Pop
from ganeti import utils
49 b5672ea0 Iustin Pop
from ganeti import cli
50 09bf5d24 Michael Hanselmann
from ganeti import pathutils
51 b5672ea0 Iustin Pop
52 b5672ea0 Iustin Pop
53 b5672ea0 Iustin Pop
options = None
54 b5672ea0 Iustin Pop
args = None
55 b5672ea0 Iustin Pop
56 b5672ea0 Iustin Pop
# Unique object to identify calls without default value
57 b5672ea0 Iustin Pop
NoDefault = object()
58 b5672ea0 Iustin Pop
59 b5672ea0 Iustin Pop
# Dictionary with instance old keys, and new hypervisor keys
60 b5672ea0 Iustin Pop
INST_HV_CHG = {
61 3ccb3a64 Michael Hanselmann
  "hvm_pae": constants.HV_PAE,
62 3ccb3a64 Michael Hanselmann
  "vnc_bind_address": constants.HV_VNC_BIND_ADDRESS,
63 3ccb3a64 Michael Hanselmann
  "initrd_path": constants.HV_INITRD_PATH,
64 3ccb3a64 Michael Hanselmann
  "hvm_nic_type": constants.HV_NIC_TYPE,
65 3ccb3a64 Michael Hanselmann
  "kernel_path": constants.HV_KERNEL_PATH,
66 3ccb3a64 Michael Hanselmann
  "hvm_acpi": constants.HV_ACPI,
67 3ccb3a64 Michael Hanselmann
  "hvm_cdrom_image_path": constants.HV_CDROM_IMAGE_PATH,
68 3ccb3a64 Michael Hanselmann
  "hvm_boot_order": constants.HV_BOOT_ORDER,
69 3ccb3a64 Michael Hanselmann
  "hvm_disk_type": constants.HV_DISK_TYPE,
70 b5672ea0 Iustin Pop
  }
71 b5672ea0 Iustin Pop
72 b5672ea0 Iustin Pop
# Instance beparams changes
73 b5672ea0 Iustin Pop
INST_BE_CHG = {
74 3ccb3a64 Michael Hanselmann
  "vcpus": constants.BE_VCPUS,
75 3ccb3a64 Michael Hanselmann
  "memory": constants.BE_MEMORY,
76 3ccb3a64 Michael Hanselmann
  "auto_balance": constants.BE_AUTO_BALANCE,
77 b5672ea0 Iustin Pop
  }
78 b5672ea0 Iustin Pop
79 b5672ea0 Iustin Pop
# Field names
80 3ccb3a64 Michael Hanselmann
F_SERIAL = "serial_no"
81 b5672ea0 Iustin Pop
82 b5672ea0 Iustin Pop
83 b5672ea0 Iustin Pop
class Error(Exception):
84 b5672ea0 Iustin Pop
  """Generic exception"""
85 b5672ea0 Iustin Pop
  pass
86 b5672ea0 Iustin Pop
87 b5672ea0 Iustin Pop
88 b5672ea0 Iustin Pop
def SsconfName(key):
89 b5672ea0 Iustin Pop
  """Returns the file name of an (old) ssconf key.
90 b5672ea0 Iustin Pop
91 b5672ea0 Iustin Pop
  """
92 b5672ea0 Iustin Pop
  return "%s/ssconf_%s" % (options.data_dir, key)
93 b5672ea0 Iustin Pop
94 b5672ea0 Iustin Pop
95 b5672ea0 Iustin Pop
def ReadFile(file_name, default=NoDefault):
96 b5672ea0 Iustin Pop
  """Reads a file.
97 b5672ea0 Iustin Pop
98 b5672ea0 Iustin Pop
  """
99 b5672ea0 Iustin Pop
  logging.debug("Reading %s", file_name)
100 b5672ea0 Iustin Pop
  try:
101 3ccb3a64 Michael Hanselmann
    fh = open(file_name, "r")
102 b5672ea0 Iustin Pop
  except IOError, err:
103 b5672ea0 Iustin Pop
    if default is not NoDefault and err.errno == errno.ENOENT:
104 b5672ea0 Iustin Pop
      return default
105 b5672ea0 Iustin Pop
    raise
106 b5672ea0 Iustin Pop
107 b5672ea0 Iustin Pop
  try:
108 b5672ea0 Iustin Pop
    return fh.read()
109 b5672ea0 Iustin Pop
  finally:
110 b5672ea0 Iustin Pop
    fh.close()
111 b5672ea0 Iustin Pop
112 b5672ea0 Iustin Pop
113 b5672ea0 Iustin Pop
def WriteFile(file_name, data):
114 b5672ea0 Iustin Pop
  """Writes a configuration file.
115 b5672ea0 Iustin Pop
116 b5672ea0 Iustin Pop
  """
117 b5672ea0 Iustin Pop
  logging.debug("Writing %s", file_name)
118 b5672ea0 Iustin Pop
  utils.WriteFile(file_name=file_name, data=data, mode=0600,
119 b5672ea0 Iustin Pop
                  dry_run=options.dry_run, backup=True)
120 b5672ea0 Iustin Pop
121 b5672ea0 Iustin Pop
122 b5672ea0 Iustin Pop
def GenerateSecret(all_secrets):
123 b5672ea0 Iustin Pop
  """Generate an unique DRBD secret.
124 b5672ea0 Iustin Pop
125 b5672ea0 Iustin Pop
  This is a copy from ConfigWriter.
126 b5672ea0 Iustin Pop
127 b5672ea0 Iustin Pop
  """
128 b5672ea0 Iustin Pop
  retries = 64
129 b5672ea0 Iustin Pop
  while retries > 0:
130 b5672ea0 Iustin Pop
    secret = utils.GenerateSecret()
131 b5672ea0 Iustin Pop
    if secret not in all_secrets:
132 b5672ea0 Iustin Pop
      break
133 b5672ea0 Iustin Pop
    retries -= 1
134 b5672ea0 Iustin Pop
  else:
135 b5672ea0 Iustin Pop
    raise Error("Can't generate unique DRBD secret")
136 b5672ea0 Iustin Pop
  return secret
137 b5672ea0 Iustin Pop
138 b5672ea0 Iustin Pop
139 b5672ea0 Iustin Pop
def SetupLogging():
140 b5672ea0 Iustin Pop
  """Configures the logging module.
141 b5672ea0 Iustin Pop
142 b5672ea0 Iustin Pop
  """
143 b5672ea0 Iustin Pop
  formatter = logging.Formatter("%(asctime)s: %(message)s")
144 b5672ea0 Iustin Pop
145 b5672ea0 Iustin Pop
  stderr_handler = logging.StreamHandler()
146 b5672ea0 Iustin Pop
  stderr_handler.setFormatter(formatter)
147 b5672ea0 Iustin Pop
  if options.debug:
148 b5672ea0 Iustin Pop
    stderr_handler.setLevel(logging.NOTSET)
149 b5672ea0 Iustin Pop
  elif options.verbose:
150 b5672ea0 Iustin Pop
    stderr_handler.setLevel(logging.INFO)
151 b5672ea0 Iustin Pop
  else:
152 b5672ea0 Iustin Pop
    stderr_handler.setLevel(logging.CRITICAL)
153 b5672ea0 Iustin Pop
154 b5672ea0 Iustin Pop
  root_logger = logging.getLogger("")
155 b5672ea0 Iustin Pop
  root_logger.setLevel(logging.NOTSET)
156 b5672ea0 Iustin Pop
  root_logger.addHandler(stderr_handler)
157 b5672ea0 Iustin Pop
158 b5672ea0 Iustin Pop
159 b5672ea0 Iustin Pop
def Cluster12To20(cluster):
160 b5672ea0 Iustin Pop
  """Upgrades the cluster object from 1.2 to 2.0.
161 b5672ea0 Iustin Pop
162 b5672ea0 Iustin Pop
  """
163 b5672ea0 Iustin Pop
  logging.info("Upgrading the cluster object")
164 b5672ea0 Iustin Pop
  # Upgrade the configuration version
165 3ccb3a64 Michael Hanselmann
  if "config_version" in cluster:
166 3ccb3a64 Michael Hanselmann
    del cluster["config_version"]
167 b5672ea0 Iustin Pop
168 b5672ea0 Iustin Pop
  # Add old ssconf keys back to config
169 b5672ea0 Iustin Pop
  logging.info(" - importing ssconf keys")
170 3ccb3a64 Michael Hanselmann
  for key in ("master_node", "master_ip", "master_netdev", "cluster_name"):
171 b5672ea0 Iustin Pop
    if key not in cluster:
172 b5672ea0 Iustin Pop
      cluster[key] = ReadFile(SsconfName(key)).strip()
173 b5672ea0 Iustin Pop
174 3ccb3a64 Michael Hanselmann
  if "default_hypervisor" not in cluster:
175 3ccb3a64 Michael Hanselmann
    old_hyp = ReadFile(SsconfName("hypervisor")).strip()
176 b5672ea0 Iustin Pop
    if old_hyp == "xen-3.0":
177 b5672ea0 Iustin Pop
      hyp = "xen-pvm"
178 b5672ea0 Iustin Pop
    elif old_hyp == "xen-hvm-3.1":
179 b5672ea0 Iustin Pop
      hyp = "xen-hvm"
180 b5672ea0 Iustin Pop
    elif old_hyp == "fake":
181 b5672ea0 Iustin Pop
      hyp = "fake"
182 b5672ea0 Iustin Pop
    else:
183 b5672ea0 Iustin Pop
      raise Error("Unknown old hypervisor name '%s'" % old_hyp)
184 b5672ea0 Iustin Pop
185 b5672ea0 Iustin Pop
    logging.info("Setting the default and enabled hypervisor")
186 3ccb3a64 Michael Hanselmann
    cluster["default_hypervisor"] = hyp
187 3ccb3a64 Michael Hanselmann
    cluster["enabled_hypervisors"] = [hyp]
188 b5672ea0 Iustin Pop
189 b5672ea0 Iustin Pop
  # hv/be params
190 3ccb3a64 Michael Hanselmann
  if "hvparams" not in cluster:
191 b5672ea0 Iustin Pop
    logging.info(" - adding hvparams")
192 3ccb3a64 Michael Hanselmann
    cluster["hvparams"] = constants.HVC_DEFAULTS
193 3ccb3a64 Michael Hanselmann
  if "beparams" not in cluster:
194 b5672ea0 Iustin Pop
    logging.info(" - adding beparams")
195 3ccb3a64 Michael Hanselmann
    cluster["beparams"] = {constants.PP_DEFAULT: constants.BEC_DEFAULTS}
196 b5672ea0 Iustin Pop
197 b5672ea0 Iustin Pop
  # file storage
198 3ccb3a64 Michael Hanselmann
  if "file_storage_dir" not in cluster:
199 09bf5d24 Michael Hanselmann
    cluster["file_storage_dir"] = pathutils.DEFAULT_FILE_STORAGE_DIR
200 b5672ea0 Iustin Pop
201 b5672ea0 Iustin Pop
  # candidate pool size
202 3ccb3a64 Michael Hanselmann
  if "candidate_pool_size" not in cluster:
203 3ccb3a64 Michael Hanselmann
    cluster["candidate_pool_size"] = constants.MASTER_POOL_SIZE_DEFAULT
204 b5672ea0 Iustin Pop
205 b5672ea0 Iustin Pop
206 b5672ea0 Iustin Pop
def Node12To20(node):
207 b5672ea0 Iustin Pop
  """Upgrades a node from 1.2 to 2.0.
208 b5672ea0 Iustin Pop
209 b5672ea0 Iustin Pop
  """
210 b5672ea0 Iustin Pop
  logging.info("Upgrading node %s", node['name'])
211 b5672ea0 Iustin Pop
  if F_SERIAL not in node:
212 b5672ea0 Iustin Pop
    node[F_SERIAL] = 1
213 3ccb3a64 Michael Hanselmann
  if "master_candidate" not in node:
214 3ccb3a64 Michael Hanselmann
    node["master_candidate"] = True
215 3ccb3a64 Michael Hanselmann
  for key in "offline", "drained":
216 b5672ea0 Iustin Pop
    if key not in node:
217 b5672ea0 Iustin Pop
      node[key] = False
218 b5672ea0 Iustin Pop
219 b5672ea0 Iustin Pop
220 b5672ea0 Iustin Pop
def Instance12To20(drbd_minors, secrets, hypervisor, instance):
221 b5672ea0 Iustin Pop
  """Upgrades an instance from 1.2 to 2.0.
222 b5672ea0 Iustin Pop
223 b5672ea0 Iustin Pop
  """
224 b5672ea0 Iustin Pop
  if F_SERIAL not in instance:
225 b5672ea0 Iustin Pop
    instance[F_SERIAL] = 1
226 b5672ea0 Iustin Pop
227 3ccb3a64 Michael Hanselmann
  if "hypervisor" not in instance:
228 3ccb3a64 Michael Hanselmann
    instance["hypervisor"] = hypervisor
229 b5672ea0 Iustin Pop
230 b5672ea0 Iustin Pop
  # hvparams changes
231 3ccb3a64 Michael Hanselmann
  if "hvparams" not in instance:
232 3ccb3a64 Michael Hanselmann
    instance["hvparams"] = hvp = {}
233 b5672ea0 Iustin Pop
  for old, new in INST_HV_CHG.items():
234 b5672ea0 Iustin Pop
    if old in instance:
235 b5672ea0 Iustin Pop
      if (instance[old] is not None and
236 b5672ea0 Iustin Pop
          instance[old] != constants.VALUE_DEFAULT and # no longer valid in 2.0
237 b5672ea0 Iustin Pop
          new in constants.HVC_DEFAULTS[hypervisor]):
238 b5672ea0 Iustin Pop
        hvp[new] = instance[old]
239 b5672ea0 Iustin Pop
      del instance[old]
240 b5672ea0 Iustin Pop
241 b5672ea0 Iustin Pop
  # beparams changes
242 3ccb3a64 Michael Hanselmann
  if "beparams" not in instance:
243 3ccb3a64 Michael Hanselmann
    instance["beparams"] = bep = {}
244 b5672ea0 Iustin Pop
  for old, new in INST_BE_CHG.items():
245 b5672ea0 Iustin Pop
    if old in instance:
246 b5672ea0 Iustin Pop
      if instance[old] is not None:
247 b5672ea0 Iustin Pop
        bep[new] = instance[old]
248 b5672ea0 Iustin Pop
      del instance[old]
249 b5672ea0 Iustin Pop
250 b5672ea0 Iustin Pop
  # disk changes
251 3ccb3a64 Michael Hanselmann
  for disk in instance["disks"]:
252 b5672ea0 Iustin Pop
    Disk12To20(drbd_minors, secrets, disk)
253 b5672ea0 Iustin Pop
254 b5672ea0 Iustin Pop
  # other instance changes
255 3ccb3a64 Michael Hanselmann
  if "status" in instance:
256 3ccb3a64 Michael Hanselmann
    instance["admin_up"] = instance["status"] == "up"
257 3ccb3a64 Michael Hanselmann
    del instance["status"]
258 b5672ea0 Iustin Pop
259 b5672ea0 Iustin Pop
260 b5672ea0 Iustin Pop
def Disk12To20(drbd_minors, secrets, disk):
261 b5672ea0 Iustin Pop
  """Upgrades a disk from 1.2 to 2.0.
262 b5672ea0 Iustin Pop
263 b5672ea0 Iustin Pop
  """
264 3ccb3a64 Michael Hanselmann
  if "mode" not in disk:
265 3ccb3a64 Michael Hanselmann
    disk["mode"] = constants.DISK_RDWR
266 3ccb3a64 Michael Hanselmann
  if disk["dev_type"] == constants.LD_DRBD8:
267 3ccb3a64 Michael Hanselmann
    old_lid = disk["logical_id"]
268 b5672ea0 Iustin Pop
    for node in old_lid[:2]:
269 b5672ea0 Iustin Pop
      if node not in drbd_minors:
270 b5672ea0 Iustin Pop
        raise Error("Can't find node '%s' while upgrading disk" % node)
271 b5672ea0 Iustin Pop
      drbd_minors[node] += 1
272 b5672ea0 Iustin Pop
      minor = drbd_minors[node]
273 b5672ea0 Iustin Pop
      old_lid.append(minor)
274 b5672ea0 Iustin Pop
    old_lid.append(GenerateSecret(secrets))
275 3ccb3a64 Michael Hanselmann
    del disk["physical_id"]
276 3ccb3a64 Michael Hanselmann
  if disk["children"]:
277 3ccb3a64 Michael Hanselmann
    for child in disk["children"]:
278 b5672ea0 Iustin Pop
      Disk12To20(drbd_minors, secrets, child)
279 b5672ea0 Iustin Pop
280 b5672ea0 Iustin Pop
281 b5672ea0 Iustin Pop
def main():
282 b5672ea0 Iustin Pop
  """Main program.
283 b5672ea0 Iustin Pop
284 b5672ea0 Iustin Pop
  """
285 b459a848 Andrea Spadaccini
  # pylint: disable=W0603
286 b5672ea0 Iustin Pop
  global options, args
287 b5672ea0 Iustin Pop
288 b5672ea0 Iustin Pop
  program = os.path.basename(sys.argv[0])
289 b5672ea0 Iustin Pop
290 b5672ea0 Iustin Pop
  # Option parsing
291 b5672ea0 Iustin Pop
  parser = optparse.OptionParser(usage="%prog [--debug|--verbose] [--force]")
292 3ccb3a64 Michael Hanselmann
  parser.add_option("--dry-run", dest="dry_run",
293 b5672ea0 Iustin Pop
                    action="store_true",
294 b5672ea0 Iustin Pop
                    help="Try to do the conversion, but don't write"
295 b5672ea0 Iustin Pop
                         " output file")
296 b5672ea0 Iustin Pop
  parser.add_option(cli.FORCE_OPT)
297 b5672ea0 Iustin Pop
  parser.add_option(cli.DEBUG_OPT)
298 b5672ea0 Iustin Pop
  parser.add_option(cli.VERBOSE_OPT)
299 3ccb3a64 Michael Hanselmann
  parser.add_option("--path", help="Convert configuration in this"
300 09bf5d24 Michael Hanselmann
                    " directory instead of '%s'" % pathutils.DATA_DIR,
301 09bf5d24 Michael Hanselmann
                    default=pathutils.DATA_DIR, dest="data_dir")
302 b5672ea0 Iustin Pop
  (options, args) = parser.parse_args()
303 b5672ea0 Iustin Pop
304 b5672ea0 Iustin Pop
  # We need to keep filenames locally because they might be renamed between
305 b5672ea0 Iustin Pop
  # versions.
306 0cddd44d Iustin Pop
  options.data_dir = os.path.abspath(options.data_dir)
307 b5672ea0 Iustin Pop
  options.CONFIG_DATA_PATH = options.data_dir + "/config.data"
308 b5672ea0 Iustin Pop
  options.SERVER_PEM_PATH = options.data_dir + "/server.pem"
309 b5672ea0 Iustin Pop
  options.KNOWN_HOSTS_PATH = options.data_dir + "/known_hosts"
310 b5672ea0 Iustin Pop
  options.RAPI_CERT_FILE = options.data_dir + "/rapi.pem"
311 b5672ea0 Iustin Pop
312 b5672ea0 Iustin Pop
  SetupLogging()
313 b5672ea0 Iustin Pop
314 b5672ea0 Iustin Pop
  # Option checking
315 b5672ea0 Iustin Pop
  if args:
316 b5672ea0 Iustin Pop
    raise Error("No arguments expected")
317 b5672ea0 Iustin Pop
318 b5672ea0 Iustin Pop
  if not options.force:
319 b5672ea0 Iustin Pop
    usertext = ("%s MUST be run on the master node. Is this the master"
320 b5672ea0 Iustin Pop
                " node and are ALL instances down?" % program)
321 b5672ea0 Iustin Pop
    if not cli.AskUser(usertext):
322 b5672ea0 Iustin Pop
      sys.exit(1)
323 b5672ea0 Iustin Pop
324 b5672ea0 Iustin Pop
  # Check whether it's a Ganeti configuration directory
325 b5672ea0 Iustin Pop
  if not (os.path.isfile(options.CONFIG_DATA_PATH) and
326 b5672ea0 Iustin Pop
          os.path.isfile(options.SERVER_PEM_PATH) or
327 b5672ea0 Iustin Pop
          os.path.isfile(options.KNOWN_HOSTS_PATH)):
328 b5672ea0 Iustin Pop
    raise Error(("%s does not seem to be a known Ganeti configuration"
329 b5672ea0 Iustin Pop
                 " directory") % options.data_dir)
330 b5672ea0 Iustin Pop
331 3ccb3a64 Michael Hanselmann
  config_version = ReadFile(SsconfName("config_version"), "1.2").strip()
332 b5672ea0 Iustin Pop
  logging.info("Found configuration version %s", config_version)
333 b5672ea0 Iustin Pop
334 b5672ea0 Iustin Pop
  config_data = serializer.LoadJson(ReadFile(options.CONFIG_DATA_PATH))
335 b5672ea0 Iustin Pop
336 b5672ea0 Iustin Pop
  # Ganeti 1.2?
337 b5672ea0 Iustin Pop
  if config_version == "1.2":
338 b5672ea0 Iustin Pop
    logging.info("Found a Ganeti 1.2 configuration")
339 b5672ea0 Iustin Pop
340 b5672ea0 Iustin Pop
    cluster = config_data["cluster"]
341 b5672ea0 Iustin Pop
342 b5672ea0 Iustin Pop
    old_config_version = cluster.get("config_version", None)
343 b5672ea0 Iustin Pop
    logging.info("Found old configuration version %s", old_config_version)
344 b5672ea0 Iustin Pop
    if old_config_version not in (3, ):
345 b5672ea0 Iustin Pop
      raise Error("Unsupported configuration version: %s" %
346 b5672ea0 Iustin Pop
                  old_config_version)
347 3ccb3a64 Michael Hanselmann
    if "version" not in config_data:
348 3ccb3a64 Michael Hanselmann
      config_data["version"] = constants.BuildVersion(2, 0, 0)
349 b5672ea0 Iustin Pop
    if F_SERIAL not in config_data:
350 b5672ea0 Iustin Pop
      config_data[F_SERIAL] = 1
351 b5672ea0 Iustin Pop
352 b5672ea0 Iustin Pop
    # Make sure no instance uses remote_raid1 anymore
353 b5672ea0 Iustin Pop
    remote_raid1_instances = []
354 b5672ea0 Iustin Pop
    for instance in config_data["instances"].values():
355 b5672ea0 Iustin Pop
      if instance["disk_template"] == "remote_raid1":
356 b5672ea0 Iustin Pop
        remote_raid1_instances.append(instance["name"])
357 b5672ea0 Iustin Pop
    if remote_raid1_instances:
358 b5672ea0 Iustin Pop
      for name in remote_raid1_instances:
359 b5672ea0 Iustin Pop
        logging.error("Instance %s still using remote_raid1 disk template",
360 b5672ea0 Iustin Pop
                      name)
361 b5672ea0 Iustin Pop
      raise Error("Unable to convert configuration as long as there are"
362 b5672ea0 Iustin Pop
                  " instances using remote_raid1 disk template")
363 b5672ea0 Iustin Pop
364 b5672ea0 Iustin Pop
    # Build content of new known_hosts file
365 3ccb3a64 Michael Hanselmann
    cluster_name = ReadFile(SsconfName("cluster_name")).rstrip()
366 3ccb3a64 Michael Hanselmann
    cluster_key = cluster["rsahostkeypub"]
367 b5672ea0 Iustin Pop
    known_hosts = "%s ssh-rsa %s\n" % (cluster_name, cluster_key)
368 b5672ea0 Iustin Pop
369 b5672ea0 Iustin Pop
    Cluster12To20(cluster)
370 b5672ea0 Iustin Pop
371 b5672ea0 Iustin Pop
    # Add node attributes
372 b5672ea0 Iustin Pop
    logging.info("Upgrading nodes")
373 b5672ea0 Iustin Pop
    # stable-sort the names to have repeatable runs
374 3ccb3a64 Michael Hanselmann
    for node_name in utils.NiceSort(config_data["nodes"].keys()):
375 3ccb3a64 Michael Hanselmann
      Node12To20(config_data["nodes"][node_name])
376 b5672ea0 Iustin Pop
377 b5672ea0 Iustin Pop
    # Instance changes
378 b5672ea0 Iustin Pop
    logging.info("Upgrading instances")
379 3ccb3a64 Michael Hanselmann
    drbd_minors = dict.fromkeys(config_data["nodes"], 0)
380 b5672ea0 Iustin Pop
    secrets = set()
381 b5672ea0 Iustin Pop
    # stable-sort the names to have repeatable runs
382 3ccb3a64 Michael Hanselmann
    for instance_name in utils.NiceSort(config_data["instances"].keys()):
383 3ccb3a64 Michael Hanselmann
      Instance12To20(drbd_minors, secrets, cluster["default_hypervisor"],
384 3ccb3a64 Michael Hanselmann
                     config_data["instances"][instance_name])
385 b5672ea0 Iustin Pop
386 b5672ea0 Iustin Pop
  else:
387 b5672ea0 Iustin Pop
    logging.info("Found a Ganeti 2.0 configuration")
388 b5672ea0 Iustin Pop
389 b5672ea0 Iustin Pop
    if "config_version" in config_data["cluster"]:
390 b5672ea0 Iustin Pop
      raise Error("Inconsistent configuration: found config_data in"
391 b5672ea0 Iustin Pop
                  " configuration file")
392 b5672ea0 Iustin Pop
393 b5672ea0 Iustin Pop
    known_hosts = None
394 b5672ea0 Iustin Pop
395 b5672ea0 Iustin Pop
  try:
396 b5672ea0 Iustin Pop
    logging.info("Writing configuration file")
397 b5672ea0 Iustin Pop
    WriteFile(options.CONFIG_DATA_PATH, serializer.DumpJson(config_data))
398 b5672ea0 Iustin Pop
399 b5672ea0 Iustin Pop
    if known_hosts is not None:
400 b5672ea0 Iustin Pop
      logging.info("Writing SSH known_hosts file (%s)", known_hosts.strip())
401 b5672ea0 Iustin Pop
      WriteFile(options.KNOWN_HOSTS_PATH, known_hosts)
402 b5672ea0 Iustin Pop
403 b5672ea0 Iustin Pop
    if not options.dry_run:
404 b5672ea0 Iustin Pop
      if not os.path.exists(options.RAPI_CERT_FILE):
405 b5672ea0 Iustin Pop
        logging.debug("Writing RAPI certificate to %s", options.RAPI_CERT_FILE)
406 693843f9 Iustin Pop
        utils.GenerateSelfSignedSslCert(options.RAPI_CERT_FILE)
407 b5672ea0 Iustin Pop
408 b5672ea0 Iustin Pop
  except:
409 b5672ea0 Iustin Pop
    logging.critical("Writing configuration failed. It is probably in an"
410 b5672ea0 Iustin Pop
                     " inconsistent state and needs manual intervention.")
411 b5672ea0 Iustin Pop
    raise
412 b5672ea0 Iustin Pop
413 b5672ea0 Iustin Pop
  logging.info("Configuration file updated.")
414 b5672ea0 Iustin Pop
415 b5672ea0 Iustin Pop
416 b5672ea0 Iustin Pop
if __name__ == "__main__":
417 b5672ea0 Iustin Pop
  main()