Revision 5a8648eb

b/lib/backend.py
231 231
  for consumption here or from the node daemon.
232 232

  
233 233
  @rtype: tuple
234
  @return: master_netdev, master_ip, master_name, primary_ip_family
234
  @return: master_netdev, master_ip, master_netmask, master_name,
235
    primary_ip_family
235 236
  @raise RPCFail: in case of errors
236 237

  
237 238
  """
......
239 240
    cfg = _GetConfig()
240 241
    master_netdev = cfg.GetMasterNetdev()
241 242
    master_ip = cfg.GetMasterIP()
243
    master_netmask = cfg.GetMasterNetmask()
242 244
    master_node = cfg.GetMasterNode()
243 245
    primary_ip_family = cfg.GetPrimaryIPFamily()
244 246
  except errors.ConfigurationError, err:
245 247
    _Fail("Cluster configuration incomplete: %s", err, exc=True)
246
  return (master_netdev, master_ip, master_node, primary_ip_family)
248
  return (master_netdev, master_ip, master_netmask, master_node,
249
          primary_ip_family)
247 250

  
248 251

  
249 252
def ActivateMasterIp():
......
251 254

  
252 255
  """
253 256
  # GetMasterInfo will raise an exception if not able to return data
254
  master_netdev, master_ip, _, family = GetMasterInfo()
257
  master_netdev, master_ip, master_netmask, _, family = GetMasterInfo()
255 258

  
256 259
  err_msg = None
257 260
  if netutils.TcpPing(master_ip, constants.DEFAULT_NODED_PORT):
......
267 270
      ipcls = netutils.IP6Address
268 271

  
269 272
    result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
270
                           "%s/%d" % (master_ip, ipcls.iplen),
273
                           "%s/%s" % (master_ip, master_netmask),
271 274
                           "dev", master_netdev, "label",
272 275
                           "%s:0" % master_netdev])
273 276
    if result.failed:
......
325 328
  # need to decide in which case we fail the RPC for this
326 329

  
327 330
  # GetMasterInfo will raise an exception if not able to return data
328
  master_netdev, master_ip, _, family = GetMasterInfo()
329

  
330
  ipcls = netutils.IP4Address
331
  if family == netutils.IP6Address.family:
332
    ipcls = netutils.IP6Address
331
  master_netdev, master_ip, master_netmask, _, _ = GetMasterInfo()
333 332

  
334 333
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
335
                         "%s/%d" % (master_ip, ipcls.iplen),
334
                         "%s/%s" % (master_ip, master_netmask),
336 335
                         "dev", master_netdev])
337 336
  if result.failed:
338 337
    logging.error("Can't remove the master IP, error: %s", result.output)
......
357 356
                  result.cmd, result.exit_code, result.output)
358 357

  
359 358

  
359
def ChangeMasterNetmask(netmask):
360
  """Change the netmask of the master IP.
361

  
362
  """
363
  master_netdev, master_ip, old_netmask, _, _ = GetMasterInfo()
364
  if old_netmask == netmask:
365
    return
366

  
367
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "add",
368
                         "%s/%s" % (master_ip, netmask),
369
                         "dev", master_netdev, "label",
370
                         "%s:0" % master_netdev])
371
  if result.failed:
372
    _Fail("Could not change the master IP netmask")
373

  
374
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "address", "del",
375
                         "%s/%s" % (master_ip, old_netmask),
376
                         "dev", master_netdev, "label",
377
                         "%s:0" % master_netdev])
378
  if result.failed:
379
    _Fail("Could not change the master IP netmask")
380

  
381

  
360 382
def EtcHostsModify(mode, host, ip):
361 383
  """Modify a host entry in /etc/hosts.
362 384

  
b/lib/bootstrap.py
283 283

  
284 284

  
285 285
def InitCluster(cluster_name, mac_prefix, # pylint: disable=R0913
286
                master_netdev, file_storage_dir, shared_file_storage_dir,
287
                candidate_pool_size, secondary_ip=None, vg_name=None,
288
                beparams=None, nicparams=None, ndparams=None, hvparams=None,
289
                enabled_hypervisors=None, modify_etc_hosts=True,
286
                master_netmask, master_netdev, file_storage_dir,
287
                shared_file_storage_dir, candidate_pool_size, secondary_ip=None,
288
                vg_name=None, beparams=None, nicparams=None, ndparams=None,
289
                hvparams=None, enabled_hypervisors=None, modify_etc_hosts=True,
290 290
                modify_ssh_setup=True, maintain_node_health=False,
291 291
                drbd_helper=None, uid_pool=None, default_iallocator=None,
292 292
                primary_ip_version=None, prealloc_wipe_disks=False):
......
310 310
                               " entries: %s" % invalid_hvs,
311 311
                               errors.ECODE_INVAL)
312 312

  
313
  ipcls = None
314
  if primary_ip_version == constants.IP4_VERSION:
315
    ipcls = netutils.IP4Address
316
  elif primary_ip_version == constants.IP6_VERSION:
317
    ipcls = netutils.IP6Address
318
  else:
313
  try:
314
    ipcls = netutils.IPAddress.GetClassFromIpVersion(primary_ip_version)
315
  except errors.ProgrammerError:
319 316
    raise errors.OpPrereqError("Invalid primary ip version: %d." %
320 317
                               primary_ip_version)
321 318

  
......
359 356
                               " but it does not belong to this host." %
360 357
                               secondary_ip, errors.ECODE_ENVIRON)
361 358

  
359
  if master_netmask is not None:
360
    if not ipcls.ValidateNetmask(master_netmask):
361
      raise errors.OpPrereqError("CIDR netmask (%s) not valid for IPv%s " %
362
                                  (master_netmask, primary_ip_version))
363
  else:
364
    master_netmask = ipcls.iplen
365

  
362 366
  if vg_name is not None:
363 367
    # Check if volume group is valid
364 368
    vgstatus = utils.CheckVolumeGroupSize(utils.ListVolumeGroups(), vg_name,
......
457 461
    tcpudp_port_pool=set(),
458 462
    master_node=hostname.name,
459 463
    master_ip=clustername.ip,
464
    master_netmask=master_netmask,
460 465
    master_netdev=master_netdev,
461 466
    cluster_name=clustername.name,
462 467
    file_storage_dir=file_storage_dir,
b/lib/cli.py
101 101
  "MAC_PREFIX_OPT",
102 102
  "MAINTAIN_NODE_HEALTH_OPT",
103 103
  "MASTER_NETDEV_OPT",
104
  "MASTER_NETMASK_OPT",
104 105
  "MC_OPT",
105 106
  "MIGRATION_MODE_OPT",
106 107
  "NET_OPT",
......
1008 1009
                               metavar="NETDEV",
1009 1010
                               default=None)
1010 1011

  
1012
MASTER_NETMASK_OPT = cli_option("--master-netmask", dest="master_netmask",
1013
                                help="Specify the netmask of the master IP",
1014
                                metavar="NETMASK",
1015
                                default=None)
1016

  
1011 1017
GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
1012 1018
                                help="Specify the default directory (cluster-"
1013 1019
                                "wide) for storing the file-based disks [%s]" %
b/lib/client/gnt_cluster.py
139 139
    ToStderr("Invalid primary ip version value: %s" % str(err))
140 140
    return 1
141 141

  
142
  master_netmask = opts.master_netmask
143
  try:
144
    if master_netmask is not None:
145
      master_netmask = int(master_netmask)
146
  except (ValueError, TypeError), err:
147
    ToStderr("Invalid master netmask value: %s" % str(err))
148
    return 1
149

  
142 150
  bootstrap.InitCluster(cluster_name=args[0],
143 151
                        secondary_ip=opts.secondary_ip,
144 152
                        vg_name=vg_name,
145 153
                        mac_prefix=opts.mac_prefix,
154
                        master_netmask=master_netmask,
146 155
                        master_netdev=master_netdev,
147 156
                        file_storage_dir=opts.file_storage_dir,
148 157
                        shared_file_storage_dir=opts.shared_file_storage_dir,
......
371 380
            compat.TryToRoman(result["candidate_pool_size"],
372 381
                              convert=opts.roman_integers))
373 382
  ToStdout("  - master netdev: %s", result["master_netdev"])
383
  ToStdout("  - master netmask: %s", result["master_netmask"])
374 384
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
375 385
  if result["reserved_lvs"]:
376 386
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
......
867 877
          opts.default_iallocator is not None or
868 878
          opts.reserved_lvs is not None or
869 879
          opts.master_netdev is not None or
880
          opts.master_netmask is not None or
870 881
          opts.prealloc_wipe_disks is not None):
871 882
    ToStderr("Please give at least one of the parameters.")
872 883
    return 1
......
926 937
    else:
927 938
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
928 939

  
940
  if opts.master_netmask is not None:
941
    try:
942
      opts.master_netmask = int(opts.master_netmask)
943
    except ValueError:
944
      ToStderr("The --master-netmask option expects an int parameter.")
945
      return 1
946

  
929 947
  op = opcodes.OpClusterSetParams(vg_name=vg_name,
930 948
                                  drbd_helper=drbd_helper,
931 949
                                  enabled_hypervisors=hvlist,
......
942 960
                                  default_iallocator=opts.default_iallocator,
943 961
                                  prealloc_wipe_disks=opts.prealloc_wipe_disks,
944 962
                                  master_netdev=opts.master_netdev,
963
                                  master_netmask=opts.master_netmask,
945 964
                                  reserved_lvs=opts.reserved_lvs)
946 965
  SubmitOpCode(op, opts=opts)
947 966
  return 0
......
1339 1358
  "init": (
1340 1359
    InitCluster, [ArgHost(min=1, max=1)],
1341 1360
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1342
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
1343
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
1344
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1345
     UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1361
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
1362
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT,
1363
     NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT,
1364
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1346 1365
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1347 1366
     NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT],
1348 1367
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
......
1417 1436
  "modify": (
1418 1437
    SetClusterParams, ARGS_NONE,
1419 1438
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1420
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1421
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
1422
     NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
1423
     DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT],
1439
     MASTER_NETMASK_OPT, NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT,
1440
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT,
1441
     DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT,
1442
     RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT,
1443
     NODE_PARAMS_OPT],
1424 1444
    "[opts...]",
1425 1445
    "Alters the parameters of the cluster"),
1426 1446
  "renew-crypto": (
b/lib/cmdlib.py
3367 3367
    return clustername
3368 3368

  
3369 3369

  
3370
def _ValidateNetmask(cfg, netmask):
3371
  """Checks if a netmask is valid.
3372

  
3373
  @type cfg: L{config.ConfigWriter}
3374
  @param cfg: The cluster configuration
3375
  @type netmask: int
3376
  @param netmask: the netmask to be verified
3377
  @raise errors.OpPrereqError: if the validation fails
3378

  
3379
  """
3380
  ip_family = cfg.GetPrimaryIPFamily()
3381
  try:
3382
    ipcls = netutils.IPAddress.GetClassFromIpFamily(ip_family)
3383
  except errors.ProgrammerError:
3384
    raise errors.OpPrereqError("Invalid primary ip family: %s." %
3385
                               ip_family)
3386
  if not ipcls.ValidateNetmask(netmask):
3387
    raise errors.OpPrereqError("CIDR netmask (%s) not valid" %
3388
                                (netmask))
3389

  
3390

  
3370 3391
class LUClusterSetParams(LogicalUnit):
3371 3392
  """Change the parameters of the cluster.
3372 3393

  
......
3388 3409
    if self.op.remove_uids:
3389 3410
      uidpool.CheckUidPool(self.op.remove_uids)
3390 3411

  
3412
    if self.op.master_netmask is not None:
3413
      _ValidateNetmask(self.cfg, self.op.master_netmask)
3414

  
3391 3415
  def ExpandNames(self):
3392 3416
    # FIXME: in the future maybe other cluster params won't require checking on
3393 3417
    # all nodes to be modified.
......
3697 3721
                  (self.cluster.master_netdev, self.op.master_netdev))
3698 3722
      self.cluster.master_netdev = self.op.master_netdev
3699 3723

  
3724
    if self.op.master_netmask:
3725
      master = self.cfg.GetMasterNode()
3726
      feedback_fn("Changing master IP netmask to %s" % self.op.master_netmask)
3727
      result = self.rpc.call_node_change_master_netmask(master,
3728
                                                        self.op.master_netmask)
3729
      if result.fail_msg:
3730
        msg = "Could not change the master IP netmask: %s" % result.fail_msg
3731
        self.LogWarning(msg)
3732
        feedback_fn(msg)
3733
      else:
3734
        self.cluster.master_netmask = self.op.master_netmask
3735

  
3700 3736
    self.cfg.Update(self.cluster, feedback_fn)
3701 3737

  
3702 3738
    if self.op.master_netdev:
......
5518 5554
      "ndparams": cluster.ndparams,
5519 5555
      "candidate_pool_size": cluster.candidate_pool_size,
5520 5556
      "master_netdev": cluster.master_netdev,
5557
      "master_netmask": cluster.master_netmask,
5521 5558
      "volume_group_name": cluster.volume_group_name,
5522 5559
      "drbd_usermode_helper": cluster.drbd_usermode_helper,
5523 5560
      "file_storage_dir": cluster.file_storage_dir,
b/lib/config.py
877 877
    return self._config_data.cluster.master_netdev
878 878

  
879 879
  @locking.ssynchronized(_config_lock, shared=1)
880
  def GetMasterNetmask(self):
881
    """Get the netmask of the master node for this cluster.
882

  
883
    """
884
    return self._config_data.cluster.master_netmask
885

  
886
  @locking.ssynchronized(_config_lock, shared=1)
880 887
  def GetFileStorageDir(self):
881 888
    """Get the file storage dir for this cluster.
882 889

  
......
1839 1846
      constants.SS_MASTER_CANDIDATES_IPS: mc_ips_data,
1840 1847
      constants.SS_MASTER_IP: cluster.master_ip,
1841 1848
      constants.SS_MASTER_NETDEV: cluster.master_netdev,
1849
      constants.SS_MASTER_NETMASK: str(cluster.master_netmask),
1842 1850
      constants.SS_MASTER_NODE: cluster.master_node,
1843 1851
      constants.SS_NODE_LIST: node_data,
1844 1852
      constants.SS_NODE_PRIMARY_IPS: node_pri_ips_data,
b/lib/constants.py
1343 1343
SS_MASTER_CANDIDATES_IPS = "master_candidates_ips"
1344 1344
SS_MASTER_IP = "master_ip"
1345 1345
SS_MASTER_NETDEV = "master_netdev"
1346
SS_MASTER_NETMASK = "master_netmask"
1346 1347
SS_MASTER_NODE = "master_node"
1347 1348
SS_NODE_LIST = "node_list"
1348 1349
SS_NODE_PRIMARY_IPS = "node_primary_ips"
b/lib/objects.py
1070 1070
    "master_node",
1071 1071
    "master_ip",
1072 1072
    "master_netdev",
1073
    "master_netmask",
1073 1074
    "cluster_name",
1074 1075
    "file_storage_dir",
1075 1076
    "shared_file_storage_dir",
b/lib/opcodes.py
777 777
     "Default iallocator for cluster"),
778 778
    ("master_netdev", None, ht.TOr(ht.TString, ht.TNone),
779 779
     "Master network device"),
780
    ("master_netmask", None, ht.TOr(ht.TInt, ht.TNone),
781
     "Netmask of the master IP"),
780 782
    ("reserved_lvs", None, ht.TOr(ht.TListOf(ht.TNonEmptyString), ht.TNone),
781 783
     "List of reserved LVs"),
782 784
    ("hidden_os", None, _TestClusterOsList,
b/lib/rpc.py
984 984
    return cls._StaticSingleNodeCall(node, "node_deactivate_master_ip", [])
985 985

  
986 986
  @classmethod
987
  @_RpcTimeout(_TMO_FAST)
988
  def call_node_change_master_netmask(cls, node, netmask):
989
    """Change master IP netmask.
990

  
991
    This is a single-node call.
992

  
993
    """
994
    return cls._StaticSingleNodeCall(node, "node_change_master_netmask",
995
                  [netmask])
996

  
997
  @classmethod
987 998
  @_RpcTimeout(_TMO_URGENT)
988 999
  def call_master_info(cls, node_list):
989 1000
    """Query master info.
b/lib/server/noded.py
726 726
    return backend.StopMasterDaemons()
727 727

  
728 728
  @staticmethod
729
  def perspective_node_change_master_netmask(params):
730
    """Change the master IP netmask.
731

  
732
    """
733
    return backend.ChangeMasterNetmask(params[0])
734

  
735
  @staticmethod
729 736
  def perspective_node_leave_cluster(params):
730 737
    """Cleanup after leaving a cluster.
731 738

  
b/lib/ssconf.py
152 152
  def GetMasterNetdev(self):
153 153
    return self._config_data["cluster"]["master_netdev"]
154 154

  
155
  def GetMasterNetmask(self):
156
    return self._config_data["cluster"]["master_netmask"]
157

  
155 158
  def GetFileStorageDir(self):
156 159
    return self._config_data["cluster"]["file_storage_dir"]
157 160

  
......
280 283
    constants.SS_MASTER_CANDIDATES_IPS,
281 284
    constants.SS_MASTER_IP,
282 285
    constants.SS_MASTER_NETDEV,
286
    constants.SS_MASTER_NETMASK,
283 287
    constants.SS_MASTER_NODE,
284 288
    constants.SS_NODE_LIST,
285 289
    constants.SS_NODE_PRIMARY_IPS,
......
408 412
    """
409 413
    return self._ReadFile(constants.SS_MASTER_NETDEV)
410 414

  
415
  def GetMasterNetmask(self):
416
    """Get the netdev to which we'll add the master ip.
417

  
418
    """
419
    return self._ReadFile(constants.SS_MASTER_NETMASK)
420

  
411 421
  def GetMasterNode(self):
412 422
    """Get the hostname of the master node for this cluster.
413 423

  
b/man/gnt-cluster.rst
166 166
| [{-s|--secondary-ip} *secondary\_ip*]
167 167
| [--vg-name *vg-name*]
168 168
| [--master-netdev *interface-name*]
169
| [--master-netmask *netmask*]
169 170
| [{-m|--mac-prefix} *mac-prefix*]
170 171
| [--no-lvm-storage]
171 172
| [--no-etc-hosts]
......
222 223
important that all nodes have this interface because you'll need it
223 224
for a master failover.
224 225

  
226
The ``--master-netmask`` option allows to specify a netmask for the
227
master IP. The netmask must be specified as an integer, and will be
228
interpreted as a CIDR netmask. The default value is 32 for an IPv4
229
address and 128 for an IPv6 address.
230

  
225 231
The ``-m (--mac-prefix)`` option will let you specify a three byte
226 232
prefix under which the virtual MAC addresses of your instances will be
227 233
generated. The prefix must be specified in the format ``XX:XX:XX`` and
......
431 437
| [--reserved-lvs=*NAMES*]
432 438
| [--node-parameters *ndparams*]
433 439
| [--master-netdev *interface-name*]
440
| [--master-netmask *netmask*]
434 441

  
435 442
Modify the options for the cluster.
436 443

  
......
438 445
``-H (--hypervisor-parameters)``, ``-B (--backend-parameters)``,
439 446
``--nic-parameters``, ``-C (--candidate-pool-size)``,
440 447
``--maintain-node-health``, ``--prealloc-wipe-disks``, ``--uid-pool``,
441
``--node-parameters``, ``--master-netdev`` options are described in
442
the **init** command.
448
``--node-parameters``, ``--master-netdev`` and ``--master-netmask``
449
options are described in the **init** command.
443 450

  
444 451
The ``--add-uids`` and ``--remove-uids`` options can be used to
445 452
modify the user-id pool by adding/removing a list of user-ids or

Also available in: Unified diff