Commit 5a8648eb authored by Andrea Spadaccini's avatar Andrea Spadaccini

Add cluster netmask parameter

Add the master_netmask cluster parameter, that represents the netmask of
the master IP, encoded as a CIDR suffix.

This parameter can be set via the --master-netmask of gnt-cluster init
and gnt-cluster modify. The default behaviour is to be consistent with
the old default (/32 for IPv4 and /128 for IPv6).
Signed-off-by: default avatarAndrea Spadaccini <spadaccio@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 7df2c4f0
......@@ -231,7 +231,8 @@ def GetMasterInfo():
for consumption here or from the node daemon.
@rtype: tuple
@return: master_netdev, master_ip, master_name, primary_ip_family
@return: master_netdev, master_ip, master_netmask, master_name,
primary_ip_family
@raise RPCFail: in case of errors
"""
......@@ -239,11 +240,13 @@ def GetMasterInfo():
cfg = _GetConfig()
master_netdev = cfg.GetMasterNetdev()
master_ip = cfg.GetMasterIP()
master_netmask = cfg.GetMasterNetmask()
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, primary_ip_family)
return (master_netdev, master_ip, master_netmask, master_node,
primary_ip_family)
def ActivateMasterIp():
......@@ -251,7 +254,7 @@ def ActivateMasterIp():
"""
# GetMasterInfo will raise an exception if not able to return data
master_netdev, master_ip, _, family = GetMasterInfo()
master_netdev, master_ip, master_netmask, _, family = GetMasterInfo()
err_msg = None
if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
......@@ -267,7 +270,7 @@ def ActivateMasterIp():
ipcls = netutils.IP6Address
result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
"%s/%d" % (master_ip, ipcls.iplen),
"%s/%s" % (master_ip, master_netmask),
"dev", master_netdev, "label",
"%s:0" % master_netdev])
if result.failed:
......@@ -325,14 +328,10 @@ def DeactivateMasterIp():
# 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, _, family = GetMasterInfo()
ipcls = netutils.IP4Address
if family == netutils.IP6Address.family:
ipcls = netutils.IP6Address
master_netdev, master_ip, master_netmask, _, _ = GetMasterInfo()
result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
"%s/%d" % (master_ip, ipcls.iplen),
"%s/%s" % (master_ip, master_netmask),
"dev", master_netdev])
if result.failed:
logging.error("Can't remove the master IP, error: %s", result.output)
......@@ -357,6 +356,29 @@ def StopMasterDaemons():
result.cmd, result.exit_code, result.output)
def ChangeMasterNetmask(netmask):
"""Change the netmask of the master IP.
"""
master_netdev, master_ip, old_netmask, _, _ = GetMasterInfo()
if old_netmask == netmask:
return
result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
"%s/%s" % (master_ip, netmask),
"dev", master_netdev, "label",
"%s:0" % master_netdev])
if result.failed:
_Fail("Could not change the master IP netmask")
result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
"%s/%s" % (master_ip, old_netmask),
"dev", master_netdev, "label",
"%s:0" % master_netdev])
if result.failed:
_Fail("Could not change the master IP netmask")
def EtcHostsModify(mode, host, ip):
"""Modify a host entry in /etc/hosts.
......
......@@ -283,10 +283,10 @@ def _InitFileStorage(file_storage_dir):
def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913
master_netdev, file_storage_dir, shared_file_storage_dir,
candidate_pool_size, secondary_ip=None, vg_name=None,
beparams=None, nicparams=None, ndparams=None, hvparams=None,
enabled_hypervisors=None, modify_etc_hosts=True,
master_netmask, master_netdev, file_storage_dir,
shared_file_storage_dir, candidate_pool_size, secondary_ip=None,
vg_name=None, beparams=None, nicparams=None, ndparams=None,
hvparams=None, enabled_hypervisors=None, modify_etc_hosts=True,
modify_ssh_setup=True, maintain_node_health=False,
drbd_helper=None, uid_pool=None, default_iallocator=None,
primary_ip_version=None, prealloc_wipe_disks=False):
......@@ -310,12 +310,9 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913
" entries: %s" % invalid_hvs,
errors.ECODE_INVAL)
ipcls = None
if primary_ip_version == constants.IP4_VERSION:
ipcls = netutils.IP4Address
elif primary_ip_version == constants.IP6_VERSION:
ipcls = netutils.IP6Address
else:
try:
ipcls = netutils.IPAddress.GetClassFromIpVersion(primary_ip_version)
except errors.ProgrammerError:
raise errors.OpPrereqError("Invalid primary ip version: %d." %
primary_ip_version)
......@@ -359,6 +356,13 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913
" but it does not belong to this host." %
secondary_ip, errors.ECODE_ENVIRON)
if master_netmask is not None:
if not ipcls.ValidateNetmask(master_netmask):
raise errors.OpPrereqError("CIDR netmask (%s) not valid for IPv%s " %
(master_netmask, primary_ip_version))
else:
master_netmask = ipcls.iplen
if vg_name is not None:
# Check if volume group is valid
vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(), vg_name,
......@@ -457,6 +461,7 @@ def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913
tcpudp_port_pool=set(),
master_node=hostname.name,
master_ip=clustername.ip,
master_netmask=master_netmask,
master_netdev=master_netdev,
cluster_name=clustername.name,
file_storage_dir=file_storage_dir,
......
......@@ -101,6 +101,7 @@ __all__ = [
"MAC_PREFIX_OPT",
"MAINTAIN_NODE_HEALTH_OPT",
"MASTER_NETDEV_OPT",
"MASTER_NETMASK_OPT",
"MC_OPT",
"MIGRATION_MODE_OPT",
"NET_OPT",
......@@ -1008,6 +1009,11 @@ MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
metavar="NETDEV",
default=None)
MASTER_NETMASK_OPT = cli_option("--master-netmask", dest="master_netmask",
help="Specify the netmask of the master IP",
metavar="NETMASK",
default=None)
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
help="Specify the default directory (cluster-"
"wide) for storing the file-based disks [%s]" %
......
......@@ -139,10 +139,19 @@ def InitCluster(opts, args):
ToStderr("Invalid primary ip version value: %s" % str(err))
return 1
master_netmask = opts.master_netmask
try:
if master_netmask is not None:
master_netmask = int(master_netmask)
except (ValueError, TypeError), err:
ToStderr("Invalid master netmask value: %s" % str(err))
return 1
bootstrap.InitCluster(cluster_name=args[0],
secondary_ip=opts.secondary_ip,
vg_name=vg_name,
mac_prefix=opts.mac_prefix,
master_netmask=master_netmask,
master_netdev=master_netdev,
file_storage_dir=opts.file_storage_dir,
shared_file_storage_dir=opts.shared_file_storage_dir,
......@@ -371,6 +380,7 @@ def ShowClusterConfig(opts, args):
compat.TryToRoman(result["candidate_pool_size"],
convert=opts.roman_integers))
ToStdout(" - master netdev: %s", result["master_netdev"])
ToStdout(" - master netmask: %s", result["master_netmask"])
ToStdout(" - lvm volume group: %s", result["volume_group_name"])
if result["reserved_lvs"]:
reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
......@@ -867,6 +877,7 @@ def SetClusterParams(opts, args):
opts.default_iallocator is not None or
opts.reserved_lvs is not None or
opts.master_netdev is not None or
opts.master_netmask is not None or
opts.prealloc_wipe_disks is not None):
ToStderr("Please give at least one of the parameters.")
return 1
......@@ -926,6 +937,13 @@ def SetClusterParams(opts, args):
else:
opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
if opts.master_netmask is not None:
try:
opts.master_netmask = int(opts.master_netmask)
except ValueError:
ToStderr("The --master-netmask option expects an int parameter.")
return 1
op = opcodes.OpClusterSetParams(vg_name=vg_name,
drbd_helper=drbd_helper,
enabled_hypervisors=hvlist,
......@@ -942,6 +960,7 @@ def SetClusterParams(opts, args):
default_iallocator=opts.default_iallocator,
prealloc_wipe_disks=opts.prealloc_wipe_disks,
master_netdev=opts.master_netdev,
master_netmask=opts.master_netmask,
reserved_lvs=opts.reserved_lvs)
SubmitOpCode(op, opts=opts)
return 0
......@@ -1339,10 +1358,10 @@ commands = {
"init": (
InitCluster, [ArgHost(min=1, max=1)],
[BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT,
NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT,
MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT],
"[opts...] <cluster_name>", "Initialises a new cluster configuration"),
......@@ -1417,10 +1436,11 @@ commands = {
"modify": (
SetClusterParams, ARGS_NONE,
[BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT],
MASTER_NETMASK_OPT, NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT,
MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT,
DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT,
RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT,
NODE_PARAMS_OPT],
"[opts...]",
"Alters the parameters of the cluster"),
"renew-crypto": (
......
......@@ -3367,6 +3367,27 @@ class LUClusterRename(LogicalUnit):
return clustername
def _ValidateNetmask(cfg, netmask):
"""Checks if a netmask is valid.
@type cfg: L{config.ConfigWriter}
@param cfg: The cluster configuration
@type netmask: int
@param netmask: the netmask to be verified
@raise errors.OpPrereqError: if the validation fails
"""
ip_family = cfg.GetPrimaryIPFamily()
try:
ipcls = netutils.IPAddress.GetClassFromIpFamily(ip_family)
except errors.ProgrammerError:
raise errors.OpPrereqError("Invalid primary ip family: %s." %
ip_family)
if not ipcls.ValidateNetmask(netmask):
raise errors.OpPrereqError("CIDR netmask (%s) not valid" %
(netmask))
class LUClusterSetParams(LogicalUnit):
"""Change the parameters of the cluster.
......@@ -3388,6 +3409,9 @@ class LUClusterSetParams(LogicalUnit):
if self.op.remove_uids:
uidpool.CheckUidPool(self.op.remove_uids)
if self.op.master_netmask is not None:
_ValidateNetmask(self.cfg, self.op.master_netmask)
def ExpandNames(self):
# FIXME: in the future maybe other cluster params won't require checking on
# all nodes to be modified.
......@@ -3697,6 +3721,18 @@ class LUClusterSetParams(LogicalUnit):
(self.cluster.master_netdev, self.op.master_netdev))
self.cluster.master_netdev = self.op.master_netdev
if self.op.master_netmask:
master = self.cfg.GetMasterNode()
feedback_fn("Changing master IP netmask to %s" % self.op.master_netmask)
result = self.rpc.call_node_change_master_netmask(master,
self.op.master_netmask)
if result.fail_msg:
msg = "Could not change the master IP netmask: %s" % result.fail_msg
self.LogWarning(msg)
feedback_fn(msg)
else:
self.cluster.master_netmask = self.op.master_netmask
self.cfg.Update(self.cluster, feedback_fn)
if self.op.master_netdev:
......@@ -5518,6 +5554,7 @@ class LUClusterQuery(NoHooksLU):
"ndparams": cluster.ndparams,
"candidate_pool_size": cluster.candidate_pool_size,
"master_netdev": cluster.master_netdev,
"master_netmask": cluster.master_netmask,
"volume_group_name": cluster.volume_group_name,
"drbd_usermode_helper": cluster.drbd_usermode_helper,
"file_storage_dir": cluster.file_storage_dir,
......
......@@ -876,6 +876,13 @@ class ConfigWriter:
"""
return self._config_data.cluster.master_netdev
@locking.ssynchronized(_config_lock, shared=1)
def GetMasterNetmask(self):
"""Get the netmask of the master node for this cluster.
"""
return self._config_data.cluster.master_netmask
@locking.ssynchronized(_config_lock, shared=1)
def GetFileStorageDir(self):
"""Get the file storage dir for this cluster.
......@@ -1839,6 +1846,7 @@ class ConfigWriter:
constants.SS_MASTER_CANDIDATES_IPS: mc_ips_data,
constants.SS_MASTER_IP: cluster.master_ip,
constants.SS_MASTER_NETDEV: cluster.master_netdev,
constants.SS_MASTER_NETMASK: str(cluster.master_netmask),
constants.SS_MASTER_NODE: cluster.master_node,
constants.SS_NODE_LIST: node_data,
constants.SS_NODE_PRIMARY_IPS: node_pri_ips_data,
......
......@@ -1343,6 +1343,7 @@ SS_MASTER_CANDIDATES = "master_candidates"
SS_MASTER_CANDIDATES_IPS = "master_candidates_ips"
SS_MASTER_IP = "master_ip"
SS_MASTER_NETDEV = "master_netdev"
SS_MASTER_NETMASK = "master_netmask"
SS_MASTER_NODE = "master_node"
SS_NODE_LIST = "node_list"
SS_NODE_PRIMARY_IPS = "node_primary_ips"
......
......@@ -1070,6 +1070,7 @@ class Cluster(TaggableObject):
"master_node",
"master_ip",
"master_netdev",
"master_netmask",
"cluster_name",
"file_storage_dir",
"shared_file_storage_dir",
......
......@@ -777,6 +777,8 @@ class OpClusterSetParams(OpCode):
"Default iallocator for cluster"),
("master_netdev", None, ht.TOr(ht.TString, ht.TNone),
"Master network device"),
("master_netmask", None, ht.TOr(ht.TInt, ht.TNone),
"Netmask of the master IP"),
("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone),
"List of reserved LVs"),
("hidden_os", None, _TestClusterOsList,
......
......@@ -983,6 +983,17 @@ class RpcRunner(object):
"""
return cls._StaticSingleNodeCall(node, "node_deactivate_master_ip", [])
@classmethod
@_RpcTimeout(_TMO_FAST)
def call_node_change_master_netmask(cls, node, netmask):
"""Change master IP netmask.
This is a single-node call.
"""
return cls._StaticSingleNodeCall(node, "node_change_master_netmask",
[netmask])
@classmethod
@_RpcTimeout(_TMO_URGENT)
def call_master_info(cls, node_list):
......
......@@ -725,6 +725,13 @@ class NodeHttpServer(http.server.HttpServer):
backend.DeactivateMasterIp()
return backend.StopMasterDaemons()
@staticmethod
def perspective_node_change_master_netmask(params):
"""Change the master IP netmask.
"""
return backend.ChangeMasterNetmask(params[0])
@staticmethod
def perspective_node_leave_cluster(params):
"""Cleanup after leaving a cluster.
......
......@@ -152,6 +152,9 @@ class SimpleConfigReader(object):
def GetMasterNetdev(self):
return self._config_data["cluster"]["master_netdev"]
def GetMasterNetmask(self):
return self._config_data["cluster"]["master_netmask"]
def GetFileStorageDir(self):
return self._config_data["cluster"]["file_storage_dir"]
......@@ -280,6 +283,7 @@ class SimpleStore(object):
constants.SS_MASTER_CANDIDATES_IPS,
constants.SS_MASTER_IP,
constants.SS_MASTER_NETDEV,
constants.SS_MASTER_NETMASK,
constants.SS_MASTER_NODE,
constants.SS_NODE_LIST,
constants.SS_NODE_PRIMARY_IPS,
......@@ -408,6 +412,12 @@ class SimpleStore(object):
"""
return self._ReadFile(constants.SS_MASTER_NETDEV)
def GetMasterNetmask(self):
"""Get the netdev to which we'll add the master ip.
"""
return self._ReadFile(constants.SS_MASTER_NETMASK)
def GetMasterNode(self):
"""Get the hostname of the master node for this cluster.
......
......@@ -166,6 +166,7 @@ INIT
| [{-s|--secondary-ip} *secondary\_ip*]
| [--vg-name *vg-name*]
| [--master-netdev *interface-name*]
| [--master-netmask *netmask*]
| [{-m|--mac-prefix} *mac-prefix*]
| [--no-lvm-storage]
| [--no-etc-hosts]
......@@ -222,6 +223,11 @@ interface on which the master will activate its IP address. It's
important that all nodes have this interface because you'll need it
for a master failover.
The ``--master-netmask`` option allows to specify a netmask for the
master IP. The netmask must be specified as an integer, and will be
interpreted as a CIDR netmask. The default value is 32 for an IPv4
address and 128 for an IPv6 address.
The ``-m (--mac-prefix)`` option will let you specify a three byte
prefix under which the virtual MAC addresses of your instances will be
generated. The prefix must be specified in the format ``XX:XX:XX`` and
......@@ -431,6 +437,7 @@ MODIFY
| [--reserved-lvs=*NAMES*]
| [--node-parameters *ndparams*]
| [--master-netdev *interface-name*]
| [--master-netmask *netmask*]
Modify the options for the cluster.
......@@ -438,8 +445,8 @@ The ``--vg-name``, ``--no-lvm-storarge``, ``--enabled-hypervisors``,
``-H (--hypervisor-parameters)``, ``-B (--backend-parameters)``,
``--nic-parameters``, ``-C (--candidate-pool-size)``,
``--maintain-node-health``, ``--prealloc-wipe-disks``, ``--uid-pool``,
``--node-parameters``, ``--master-netdev`` options are described in
the **init** command.
``--node-parameters``, ``--master-netdev`` and ``--master-netmask``
options are described in the **init** command.
The ``--add-uids`` and ``--remove-uids`` options can be used to
modify the user-id pool by adding/removing a list of user-ids or
......
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