X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/af2ae1c02d63e6bf96981eaf04d3ae54e4eac576..600535f0cffc11b5455ac5657cee1f680ebc547c:/lib/bootstrap.py diff --git a/lib/bootstrap.py b/lib/bootstrap.py index fe094b3..5a2c5ba 100644 --- a/lib/bootstrap.py +++ b/lib/bootstrap.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2008 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2010 Google Inc. # # 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 @@ -39,6 +39,8 @@ from ganeti import objects from ganeti import ssconf from ganeti import serializer from ganeti import hypervisor +from ganeti import bdev +from ganeti import netutils def _InitSSHSetup(): @@ -80,7 +82,8 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_confd_hmac_key, new_cds, rapi_cert_pem=None, cds=None, nodecert_file=constants.NODED_CERT_FILE, rapicert_file=constants.RAPI_CERT_FILE, - hmackey_file=constants.CONFD_HMAC_KEY): + hmackey_file=constants.CONFD_HMAC_KEY, + cds_file=constants.CLUSTER_DOMAIN_SECRET_FILE): """Updates the cluster certificates, keys and secrets. @type new_cluster_cert: bool @@ -134,22 +137,22 @@ def GenerateClusterCrypto(new_cluster_cert, new_rapi_cert, new_confd_hmac_key, # Cluster domain secret if cds: - logging.debug("Writing cluster domain secret to %s", - constants.CLUSTER_DOMAIN_SECRET_FILE) - utils.WriteFile(constants.CLUSTER_DOMAIN_SECRET_FILE, - data=cds, backup=True) + logging.debug("Writing cluster domain secret to %s", cds_file) + utils.WriteFile(cds_file, data=cds, backup=True) - elif new_cds or not os.path.exists(constants.CLUSTER_DOMAIN_SECRET_FILE): - logging.debug("Generating new cluster domain secret at %s", - constants.CLUSTER_DOMAIN_SECRET_FILE) - GenerateHmacKey(constants.CLUSTER_DOMAIN_SECRET_FILE) + elif new_cds or not os.path.exists(cds_file): + logging.debug("Generating new cluster domain secret at %s", cds_file) + GenerateHmacKey(cds_file) def _InitGanetiServerSetup(master_name): """Setup the necessary configuration for the initial node daemon. This creates the nodepass file containing the shared password for - the cluster and also generates the SSL certificate. + the cluster, generates the SSL certificate and starts the node daemon. + + @type master_name: str + @param master_name: Name of the master node """ # Generate cluster secrets @@ -212,12 +215,14 @@ def _InitFileStorage(file_storage_dir): return file_storage_dir +#pylint: disable-msg=R0913 def InitCluster(cluster_name, mac_prefix, master_netdev, file_storage_dir, candidate_pool_size, secondary_ip=None, vg_name=None, beparams=None, nicparams=None, hvparams=None, enabled_hypervisors=None, modify_etc_hosts=True, modify_ssh_setup=True, - maintain_node_health=False): + maintain_node_health=False, drbd_helper=None, + uid_pool=None, default_iallocator=None): """Initialise the cluster. @type candidate_pool_size: int @@ -238,7 +243,7 @@ def InitCluster(cluster_name, mac_prefix, " entries: %s" % invalid_hvs, errors.ECODE_INVAL) - hostname = utils.GetHostInfo() + hostname = netutils.GetHostInfo() if hostname.ip.startswith("127."): raise errors.OpPrereqError("This host's IP resolves to the private" @@ -246,25 +251,26 @@ def InitCluster(cluster_name, mac_prefix, (hostname.ip, constants.ETC_HOSTS), errors.ECODE_ENVIRON) - if not utils.OwnIpAddress(hostname.ip): + if not netutils.OwnIpAddress(hostname.ip): raise errors.OpPrereqError("Inconsistency: this host's name resolves" " to %s,\nbut this ip address does not" " belong to this host. Aborting." % hostname.ip, errors.ECODE_ENVIRON) - clustername = utils.GetHostInfo(utils.HostInfo.NormalizeName(cluster_name)) + clustername = \ + netutils.GetHostInfo(netutils.HostInfo.NormalizeName(cluster_name)) - if utils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT, + if netutils.TcpPing(clustername.ip, constants.DEFAULT_NODED_PORT, timeout=5): raise errors.OpPrereqError("Cluster IP already active. Aborting.", errors.ECODE_NOTUNIQUE) if secondary_ip: - if not utils.IsValidIP(secondary_ip): + if not netutils.IsValidIP4(secondary_ip): raise errors.OpPrereqError("Invalid secondary ip given", errors.ECODE_INVAL) if (secondary_ip != hostname.ip and - not utils.OwnIpAddress(secondary_ip)): + not netutils.OwnIpAddress(secondary_ip)): raise errors.OpPrereqError("You gave %s as secondary IP," " but it does not belong to this host." % secondary_ip, errors.ECODE_ENVIRON) @@ -280,6 +286,20 @@ def InitCluster(cluster_name, mac_prefix, " you are not using lvm" % vgstatus, errors.ECODE_INVAL) + if drbd_helper is not None: + try: + curr_helper = bdev.BaseDRBD.GetUsermodeHelper() + except errors.BlockDeviceError, err: + raise errors.OpPrereqError("Error while checking drbd helper" + " (specify --no-drbd-storage if you are not" + " using drbd): %s" % str(err), + errors.ECODE_ENVIRON) + if drbd_helper != curr_helper: + raise errors.OpPrereqError("Error: requiring %s as drbd helper but %s" + " is the current helper" % (drbd_helper, + curr_helper), + errors.ECODE_INVAL) + file_storage_dir = _InitFileStorage(file_storage_dir) if not re.match("^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$", mac_prefix): @@ -305,7 +325,7 @@ def InitCluster(cluster_name, mac_prefix, hv_class = hypervisor.GetHypervisor(hv_name) hv_class.CheckParameterSyntax(hv_params) - # set up the inter-node password and certificate + # set up the inter-node password and certificate, start noded _InitGanetiServerSetup(hostname.name) # set up ssh config and /etc/hosts @@ -318,6 +338,15 @@ def InitCluster(cluster_name, mac_prefix, if modify_ssh_setup: _InitSSHSetup() + if default_iallocator is not None: + alloc_script = utils.FindFile(default_iallocator, + constants.IALLOCATOR_SEARCH_PATH, + os.path.isfile) + if alloc_script is None: + raise errors.OpPrereqError("Invalid default iallocator script '%s'" + " specified" % default_iallocator, + errors.ECODE_INVAL) + now = time.time() # init of cluster config file @@ -340,10 +369,13 @@ def InitCluster(cluster_name, mac_prefix, candidate_pool_size=candidate_pool_size, modify_etc_hosts=modify_etc_hosts, modify_ssh_setup=modify_ssh_setup, + uid_pool=uid_pool, ctime=now, mtime=now, uuid=utils.NewUUID(), maintain_node_health=maintain_node_health, + drbd_usermode_helper=drbd_helper, + default_iallocator=default_iallocator, ) master_node_config = objects.Node(name=hostname.name, primary_ip=hostname.ip, @@ -543,7 +575,19 @@ def MasterFailover(no_voting=False): logging.error("Could not disable the master role on the old master" " %s, please disable manually: %s", old_master, msg) + master_ip = sstore.GetMasterIP() + total_timeout = 30 # Here we have a phase where no master should be running + def _check_ip(): + if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT): + raise utils.RetryAgain() + + try: + utils.Retry(_check_ip, (1, 1.5, 5), total_timeout) + except utils.RetryTimeout: + logging.warning("The master IP is still reachable after %s seconds," + " continuing but activating the master on the current" + " node will probably fail", total_timeout) # instantiate a real config writer, as we now know we have the # configuration data @@ -602,7 +646,7 @@ def GatherMasterVotes(node_list): @return: list of (node, votes) """ - myself = utils.HostInfo().name + myself = netutils.HostInfo().name try: node_list.remove(myself) except ValueError: