Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade12 @ 65b526e7

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