#
#
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 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
from ganeti import objects
from ganeti import ssconf
from ganeti import serializer
+from ganeti import netutils
_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id"
for consumption here or from the node daemon.
@rtype: tuple
- @return: master_netdev, master_ip, master_name
+ @return: master_netdev, master_ip, master_name, primary_ip_family
@raise RPCFail: in case of errors
"""
master_netdev = cfg.GetMasterNetdev()
master_ip = cfg.GetMasterIP()
master_node = cfg.GetMasterNode()
+ primary_ip_family = cfg.GetPrimaryIPFamily()
except errors.ConfigurationError, err:
_Fail("Cluster configuration incomplete: %s", err, exc=True)
- return (master_netdev, master_ip, master_node)
+ return (master_netdev, master_ip, master_node, primary_ip_family)
def StartMaster(start_daemons, no_voting):
"""Activate local node as master node.
- The function will always try activate the IP address of the master
- (unless someone else has it). It will also start the master daemons,
- based on the start_daemons parameter.
+ The function will either try activate the IP address of the master
+ (unless someone else has it) or also start the master daemons, based
+ on the start_daemons parameter.
@type start_daemons: boolean
- @param start_daemons: whether to also start the master
- daemons (ganeti-masterd and ganeti-rapi)
+ @param start_daemons: whether to start the master daemons
+ (ganeti-masterd and ganeti-rapi), or (if false) activate the
+ master ip
@type no_voting: boolean
@param no_voting: whether to start ganeti-masterd without a node vote
(if start_daemons is True), but still non-interactively
"""
# GetMasterInfo will raise an exception if not able to return data
- master_netdev, master_ip, _ = GetMasterInfo()
+ master_netdev, master_ip, _, family = GetMasterInfo()
err_msgs = []
- if utils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
- if utils.OwnIpAddress(master_ip):
- # we already have the ip:
- logging.debug("Master IP already configured, doing nothing")
- else:
- msg = "Someone else has the master ip, not activating"
- logging.error(msg)
- err_msgs.append(msg)
- else:
- result = utils.RunCmd(["ip", "address", "add", "%s/32" % master_ip,
- "dev", master_netdev, "label",
- "%s:0" % master_netdev])
- if result.failed:
- msg = "Can't activate master IP: %s" % result.output
- logging.error(msg)
- err_msgs.append(msg)
-
- result = utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev,
- "-s", master_ip, master_ip])
- # we'll ignore the exit code of arping
-
- # and now start the master and rapi daemons
+ # either start the master and rapi daemons
if start_daemons:
if no_voting:
masterd_args = "--no-voting --yes-do-it"
msg = "Can't start Ganeti master: %s" % result.output
logging.error(msg)
err_msgs.append(msg)
+ # or activate the IP
+ else:
+ if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
+ if netutils.IPAddress.Own(master_ip):
+ # we already have the ip:
+ logging.debug("Master IP already configured, doing nothing")
+ else:
+ msg = "Someone else has the master ip, not activating"
+ logging.error(msg)
+ err_msgs.append(msg)
+ else:
+ ipcls = netutils.IP4Address
+ if family == netutils.IP6Address.family:
+ ipcls = netutils.IP6Address
+
+ result = utils.RunCmd(["ip", "address", "add",
+ "%s/%d" % (master_ip, ipcls.iplen),
+ "dev", master_netdev, "label",
+ "%s:0" % master_netdev])
+ if result.failed:
+ msg = "Can't activate master IP: %s" % result.output
+ logging.error(msg)
+ err_msgs.append(msg)
+
+ # we ignore the exit code of the following cmds
+ if ipcls == netutils.IP4Address:
+ utils.RunCmd(["arping", "-q", "-U", "-c 3", "-I", master_netdev, "-s",
+ master_ip, master_ip])
+ elif ipcls == netutils.IP6Address:
+ try:
+ utils.RunCmd(["ndisc6", "-q", "-r 3", master_ip, master_netdev])
+ except errors.OpExecError:
+ # TODO: Better error reporting
+ logging.warning("Can't execute ndisc6, please install if missing")
if err_msgs:
_Fail("; ".join(err_msgs))
# need to decide in which case we fail the RPC for this
# GetMasterInfo will raise an exception if not able to return data
- master_netdev, master_ip, _ = GetMasterInfo()
+ master_netdev, master_ip, _, family = GetMasterInfo()
+
+ ipcls = netutils.IP4Address
+ if family == netutils.IP6Address.family:
+ ipcls = netutils.IP6Address
- result = utils.RunCmd(["ip", "address", "del", "%s/32" % master_ip,
+ result = utils.RunCmd(["ip", "address", "del",
+ "%s/%d" % (master_ip, ipcls.iplen),
"dev", master_netdev])
if result.failed:
logging.error("Can't remove the master IP, error: %s", result.output)
result.cmd, result.exit_code, result.output)
-def AddNode(dsa, dsapub, rsa, rsapub, sshkey, sshpub):
- """Joins this node to the cluster.
-
- This does the following:
- - updates the hostkeys of the machine (rsa and dsa)
- - adds the ssh private key to the user
- - adds the ssh public key to the users' authorized_keys file
-
- @type dsa: str
- @param dsa: the DSA private key to write
- @type dsapub: str
- @param dsapub: the DSA public key to write
- @type rsa: str
- @param rsa: the RSA private key to write
- @type rsapub: str
- @param rsapub: the RSA public key to write
- @type sshkey: str
- @param sshkey: the SSH private key to write
- @type sshpub: str
- @param sshpub: the SSH public key to write
- @rtype: boolean
- @return: the success of the operation
+def EtcHostsModify(mode, host, ip):
+ """Modify a host entry in /etc/hosts.
- """
- sshd_keys = [(constants.SSH_HOST_RSA_PRIV, rsa, 0600),
- (constants.SSH_HOST_RSA_PUB, rsapub, 0644),
- (constants.SSH_HOST_DSA_PRIV, dsa, 0600),
- (constants.SSH_HOST_DSA_PUB, dsapub, 0644)]
- for name, content, mode in sshd_keys:
- utils.WriteFile(name, data=content, mode=mode)
+ @param mode: The mode to operate. Either add or remove entry
+ @param host: The host to operate on
+ @param ip: The ip associated with the entry
- try:
- priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS,
- mkdir=True)
- except errors.OpExecError, err:
- _Fail("Error while processing user ssh files: %s", err, exc=True)
-
- for name, content in [(priv_key, sshkey), (pub_key, sshpub)]:
- utils.WriteFile(name, data=content, mode=0600)
-
- utils.AddAuthorizedKey(auth_keys, sshpub)
-
- result = utils.RunCmd([constants.DAEMON_UTIL, "reload-ssh-keys"])
- if result.failed:
- _Fail("Unable to reload SSH keys (command %r, exit code %s, output %r)",
- result.cmd, result.exit_code, result.output)
+ """
+ if mode == constants.ETC_HOSTS_ADD:
+ if not ip:
+ RPCFail("Mode 'add' needs 'ip' parameter, but parameter not"
+ " present")
+ utils.AddHostToEtcHosts(host, ip)
+ elif mode == constants.ETC_HOSTS_REMOVE:
+ if ip:
+ RPCFail("Mode 'remove' does not allow 'ip' parameter, but"
+ " parameter is present")
+ utils.RemoveHostFromEtcHosts(host)
+ else:
+ RPCFail("Mode not supported")
def LeaveCluster(modify_ssh_setup):
"""
result = {}
- my_name = utils.HostInfo().name
- port = utils.GetDaemonPort(constants.NODED)
+ my_name = netutils.Hostname.GetSysName()
+ port = netutils.GetDaemonPort(constants.NODED)
if constants.NV_HYPERVISOR in what:
result[constants.NV_HYPERVISOR] = tmp = {}
else:
for name, pip, sip in what[constants.NV_NODENETTEST]:
fail = []
- if not utils.TcpPing(pip, port, source=my_pip):
+ if not netutils.TcpPing(pip, port, source=my_pip):
fail.append("primary")
if sip != pip:
- if not utils.TcpPing(sip, port, source=my_sip):
+ if not netutils.TcpPing(sip, port, source=my_sip):
fail.append("secondary")
if fail:
tmp[name] = ("failure using the %s interface(s)" %
# rest of the function)
master_name, master_ip = what[constants.NV_MASTERIP]
if master_name == my_name:
- source = constants.LOCALHOST_IP_ADDRESS
+ source = constants.IP4_ADDRESS_LOCALHOST
else:
source = None
- result[constants.NV_MASTERIP] = utils.TcpPing(master_ip, port,
+ result[constants.NV_MASTERIP] = netutils.TcpPing(master_ip, port,
source=source)
if constants.NV_LVLIST in what:
used_minors = str(err)
result[constants.NV_DRBDLIST] = used_minors
+ if constants.NV_DRBDHELPER in what:
+ status = True
+ try:
+ payload = bdev.BaseDRBD.GetUsermodeHelper()
+ except errors.BlockDeviceError, err:
+ logging.error("Can't get DRBD usermode helper: %s", str(err))
+ status = False
+ payload = str(err)
+ result[constants.NV_DRBDHELPER] = (status, payload)
+
if constants.NV_NODESETUP in what:
result[constants.NV_NODESETUP] = tmpr = []
if not os.path.isdir("/sys/block") or not os.path.isdir("/sys/class/net"):
if constants.NV_TIME in what:
result[constants.NV_TIME] = utils.SplitTime(time.time())
+ if constants.NV_OSLIST in what:
+ result[constants.NV_OSLIST] = DiagnoseOS()
+
return result
for idx in range(len(instance.disks)):
link_name = _GetBlockDevSymlinkPath(iname, idx)
if not os.path.islink(link_name):
- _Fail("Instance %s was not restarted since ganeti 1.2.5", iname)
+ logging.warning("Instance %s is missing symlink %s for disk %d",
+ iname, link_name, idx)
def GetAllInstancesInfo(hypervisor_list):
search (if not given defaults to
L{constants.OS_SEARCH_PATH})
@rtype: list of L{objects.OS}
- @return: a list of tuples (name, path, status, diagnose, variants)
- for all (potential) OSes under all search paths, where:
+ @return: a list of tuples (name, path, status, diagnose, variants,
+ parameters, api_version) for all (potential) OSes under all
+ search paths, where:
- name is the (potential) OS name
- path is the full path to the OS
- status True/False is the validity of the OS
- diagnose is the error message for an invalid OS, otherwise empty
- variants is a list of supported OS variants, if any
- parameters is a list of (name, help) parameters, if any
+ - api_version is a list of support OS API versions
"""
if top_dirs is None:
diagnose = ""
variants = os_inst.supported_variants
parameters = os_inst.supported_parameters
+ api_versions = os_inst.api_versions
else:
diagnose = os_inst
- variants = parameters = []
- result.append((name, os_path, status, diagnose, variants, parameters))
+ variants = parameters = api_versions = []
+ result.append((name, os_path, status, diagnose, variants,
+ parameters, api_versions))
return result
export_script=os_files[constants.OS_SCRIPT_EXPORT],
import_script=os_files[constants.OS_SCRIPT_IMPORT],
rename_script=os_files[constants.OS_SCRIPT_RENAME],
- verify_script=os_files[constants.OS_SCRIPT_VERIFY],
+ verify_script=os_files.get(constants.OS_SCRIPT_VERIFY,
+ None),
supported_variants=variants,
supported_parameters=parameters,
api_versions=api_versions)
for name, value in instance.beparams.items():
config.set(constants.INISECT_BEP, name, str(value))
+ config.add_section(constants.INISECT_OSP)
+ for name, value in instance.osparams.items():
+ config.set(constants.INISECT_OSP, name, str(value))
+
utils.WriteFile(utils.PathJoin(destdir, constants.EXPORT_CONF_FILE),
data=config.Dumps())
shutil.rmtree(finaldestdir, ignore_errors=True)
else:
return False
+ if max(tbv.api_versions) < constants.OS_API_V20:
+ return True
+
if constants.OS_VALIDATE_PARAMETERS in checks:
_CheckOSPList(tbv, osparams.keys())
"""
(key_pem, cert_pem) = \
- utils.GenerateSelfSignedX509Cert(utils.HostInfo.SysName(),
+ utils.GenerateSelfSignedX509Cert(netutils.Hostname.GetSysName(),
min(validity, _MAX_SSL_CERT_VALIDITY))
cert_dir = tempfile.mkdtemp(dir=cryptodir,
"""
# set the correct physical ID
- my_name = utils.HostInfo().name
+ my_name = netutils.Hostname.GetSysName()
for cf in disks:
cf.SetPhysicalID(my_name, nodes_ip)
return (alldone, min_resync)
+def GetDrbdUsermodeHelper():
+ """Returns DRBD usermode helper currently configured.
+
+ """
+ try:
+ return bdev.BaseDRBD.GetUsermodeHelper()
+ except errors.BlockDeviceError, err:
+ _Fail(str(err))
+
+
def PowercycleNode(hypervisor_type):
"""Hard-powercycle the node.