Statistics
| Branch: | Tag: | Revision:

root / tools / cfgupgrade @ ac4d25b6

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