Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade12 @ 1817dca9

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