Commit a421fdeb authored by Iustin Pop's avatar Iustin Pop
Browse files

First run at cfgupgrade for 2.0 upgrades

This patch makes cfgupgrade work on empty cluster (i.e. no instances),
up to a point that the config file can be converted from 1.2 to 2.0.
This is not yet complete, though.

Reviewed-by: ultrotter
parent 75615bd3
#!/usr/bin/python #!/usr/bin/python
# #
# Copyright (C) 2007, 2008 Google Inc. # Copyright (C) 2007, 2008, 2009 Google Inc.
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
"""Tool to upgrade the configuration file. """Tool to upgrade the configuration file.
This code handles only the types supported by simplejson. As an example, "set" This code handles only the types supported by simplejson. As an
is a "list". example, 'set' is a 'list'.
""" """
...@@ -39,6 +39,7 @@ from ganeti import constants ...@@ -39,6 +39,7 @@ from ganeti import constants
from ganeti import serializer from ganeti import serializer
from ganeti import utils from ganeti import utils
from ganeti import cli from ganeti import cli
from ganeti import bootstrap
# We need to keep filenames locally because they might be renamed between # We need to keep filenames locally because they might be renamed between
...@@ -61,6 +62,13 @@ class Error(Exception): ...@@ -61,6 +62,13 @@ class Error(Exception):
pass pass
def SsconfName(key):
"""Returns the file name of an (old) ssconf key.
"""
return "%s/ssconf_%s" % (constants.DATA_DIR, key)
def ReadFile(file_name, default=NoDefault): def ReadFile(file_name, default=NoDefault):
"""Reads a file. """Reads a file.
...@@ -108,6 +116,63 @@ def SetupLogging(): ...@@ -108,6 +116,63 @@ def SetupLogging():
root_logger.addHandler(stderr_handler) root_logger.addHandler(stderr_handler)
def Cluster12To20(cluster):
"""Upgrades the cluster object from 1.2 to 2.0.
"""
logging.info("Upgrading the cluster object")
# Upgrade the configuration version
if 'config_version' in cluster:
del cluster['config_version']
# Add old ssconf keys back to config
logging.info(" - importing ssconf keys")
for key in ('master_node', 'master_ip', 'master_netdev', 'cluster_name'):
if key not in cluster:
cluster[key] = ReadFile(SsconfName(key)).strip()
if 'default_hypervisor' not in cluster:
old_hyp = ReadFile(SsconfName('hypervisor')).strip()
if old_hyp == "xen-3.0":
hyp = "xen-pvm"
elif old_hyp == "xen-hvm-3.1":
hyp = "xen-hvm"
elif old_hyp == "fake":
hyp = "fake"
else:
raise Error("Unknown old hypervisor name '%s'" % old_hyp)
logging.info("Setting the default and enabled hypervisor")
cluster['default_hypervisor'] = hyp
cluster['enabled_hypervisors'] = [hyp]
# hv/be params
if 'hvparams' not in cluster:
logging.info(" - adding hvparams")
cluster['hvparams'] = constants.HVC_DEFAULTS
if 'beparams' not in cluster:
logging.info(" - adding beparams")
cluster['beparams'] = {constants.BEGR_DEFAULT: constants.BEC_DEFAULTS}
# file storage
if 'file_storage_dir' not in cluster:
cluster['file_storage_dir'] = constants.DEFAULT_FILE_STORAGE_DIR
def Node12To20(node):
"""Upgrades a node from 1.2 to 2.0.
"""
logging.info("Upgrading node %s" % node['name'])
if 'serial_no' not in node:
node['serial_no'] = 1
if 'master_candidate' not in node:
node['master_candidate'] = True
for key in 'offline', 'drained':
if key not in node:
node[key] = False
def main(): def main():
"""Main program. """Main program.
...@@ -124,7 +189,7 @@ def main(): ...@@ -124,7 +189,7 @@ def main():
" output file") " output file")
parser.add_option(cli.FORCE_OPT) parser.add_option(cli.FORCE_OPT)
parser.add_option(cli.DEBUG_OPT) parser.add_option(cli.DEBUG_OPT)
parser.add_option('--verbose', dest='verbose', parser.add_option('-v', '--verbose', dest='verbose',
action="store_true", action="store_true",
help="Verbose output") help="Verbose output")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
...@@ -136,8 +201,8 @@ def main(): ...@@ -136,8 +201,8 @@ def main():
raise Error("No arguments expected") raise Error("No arguments expected")
if not options.force: if not options.force:
usertext = ("%s MUST run on the master node. Is this the master" usertext = ("%s MUST be run on the master node. Is this the master"
" node?" % program) " node and are ALL instances down?" % program)
if not cli.AskUser(usertext): if not cli.AskUser(usertext):
sys.exit(1) sys.exit(1)
...@@ -157,11 +222,17 @@ def main(): ...@@ -157,11 +222,17 @@ def main():
if config_version == "1.2": if config_version == "1.2":
logging.info("Found a Ganeti 1.2 configuration") logging.info("Found a Ganeti 1.2 configuration")
old_config_version = config_data["cluster"].get("config_version", None) cluster = config_data["cluster"]
old_config_version = cluster.get("config_version", None)
logging.info("Found old configuration version %s", old_config_version) logging.info("Found old configuration version %s", old_config_version)
if old_config_version not in (3, ): if old_config_version not in (3, ):
raise Error("Unsupported configuration version: %s" % raise Error("Unsupported configuration version: %s" %
old_config_version) old_config_version)
if 'version' not in config_data:
config_data['version'] = constants.BuildVersion(2, 0, 0)
if 'serial_no' not in config_data:
config_data['serial_no'] = 1
# Make sure no instance uses remote_raid1 anymore # Make sure no instance uses remote_raid1 anymore
remote_raid1_instances = [] remote_raid1_instances = []
...@@ -174,15 +245,24 @@ def main(): ...@@ -174,15 +245,24 @@ def main():
raise Error("Unable to convert configuration as long as there are" raise Error("Unable to convert configuration as long as there are"
" instances using remote_raid1 disk template") " instances using remote_raid1 disk template")
# The configuration version will be stored in a ssconf file
if 'config_version' in config_data['cluster']:
del config_data['cluster']['config_version']
# Build content of new known_hosts file # Build content of new known_hosts file
cluster_name = ReadFile(SSCONF_CLUSTER_NAME_PATH).rstrip() cluster_name = ReadFile(SSCONF_CLUSTER_NAME_PATH).rstrip()
cluster_key = config_data['cluster']['rsahostkeypub'] cluster_key = cluster['rsahostkeypub']
known_hosts = "%s ssh-rsa %s\n" % (cluster_name, cluster_key) known_hosts = "%s ssh-rsa %s\n" % (cluster_name, cluster_key)
Cluster12To20(cluster)
# Add node attributes
logging.info("Upgrading nodes")
# stable-sort the names to have repeatable runs
for node_name in utils.NiceSort(config_data['nodes'].keys()):
Node12To20(config_data['nodes'][node_name])
# instance changes
# TODO: add instance upgrade
for instance in config_data['instances'].values():
pass
else: else:
logging.info("Found a Ganeti 2.0 configuration") logging.info("Found a Ganeti 2.0 configuration")
...@@ -192,18 +272,18 @@ def main(): ...@@ -192,18 +272,18 @@ def main():
known_hosts = None known_hosts = None
config_version_str = "%s\n" % constants.BuildVersion(2, 0, 0)
try: try:
logging.info("Writing configuration file") logging.info("Writing configuration file")
WriteFile(CONFIG_DATA_PATH, serializer.DumpJson(config_data)) WriteFile(CONFIG_DATA_PATH, serializer.DumpJson(config_data))
logging.info("Writing configuration version %s",
config_version_str.strip())
WriteFile(SSCONF_CONFIG_VERSION_PATH, config_version_str)
if known_hosts is not None: if known_hosts is not None:
logging.info("Writing SSH known_hosts file (%s)", known_hosts.strip()) logging.info("Writing SSH known_hosts file (%s)", known_hosts.strip())
WriteFile(KNOWN_HOSTS_PATH, known_hosts) WriteFile(KNOWN_HOSTS_PATH, known_hosts)
if not options.dry_run:
if not os.path.exists(constants.RAPI_CERT_FILE):
bootstrap._GenerateSelfSignedSslCert(constants.RAPI_CERT_FILE)
except: except:
logging.critical("Writing configuration failed. It is proably in an" logging.critical("Writing configuration failed. It is proably in an"
" inconsistent state and needs manual intervention.") " inconsistent state and needs manual intervention.")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment