Commit 0e82dcf9 authored by Andrea Spadaccini's avatar Andrea Spadaccini
Browse files

Merge branch 'devel-2.5'



* devel-2.5: (24 commits)
  LUInstanceCreate: Release unused node locks
  htools: rework message display construction
  hbal: handle empty node groups
  Document OpNodeMigrate's result for RAPI
  Ensure unused ports return to the free port pool
  Re-wrap a paragraph to eliminate a sphinx warning
  Fix newer pylint's E0611 error in compat.py
  Fail if node/group evacuation can't evacuate instances
  Update init script description
  LUInstanceRename: Compare name with name
  LUClusterRepairDiskSizes: Acquire instance locks in exclusive mode
  Update synopsis for “gnt-cluster repair-disk-sizes”
  Move hooks PATH environment variable to constants
  Check the results of master IP RPCs
  Add documentation for the master IP hooks
  Add master IP turnup and turndown hooks
  Add RunLocalHooks decorator
  Generalize HooksMaster
  Update NEWS for 2.5.0~rc4
  Bump version to 2.5.0~rc4
  ...

Conflicts:
	NEWS
	doc/hooks.rst
	lib/backend.py
	lib/cmdlib.py
	lib/constants.py
Signed-off-by: default avatarAndrea Spadaccini <spadaccio@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parents edc282ad 0c1441eb
......@@ -9,10 +9,10 @@ Version 2.6.0 beta 1
- Deprecated ``admin_up`` field. Instead, ``admin_state`` is introduced,
with 3 possible values -- ``up``,``down`` and ``offline``.
Version 2.5.0 rc2
Version 2.5.0 rc4
-----------------
*(Released Tue, 18 Oct 2011)*
*(Released Thu, 27 Oct 2011)*
Incompatible/important changes and bugfixes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -127,6 +127,8 @@ Misc
- :doc:`RAPI <rapi>` documentation now has detailed parameter
descriptions.
- Some opcode/job results are now also documented, see :doc:`RAPI
<rapi>`.
- A lockset's internal lock is now also visible in lock monitor.
- Log messages from job queue workers now contain information about the
......@@ -137,6 +139,22 @@ Misc
- DRBD metadata volumes are overwritten with zeros during disk creation.
Version 2.5.0 rc3
-----------------
*(Released Wed, 26 Oct 2011)*
This was the third release candidate of the 2.5 series.
Version 2.5.0 rc2
-----------------
*(Released Tue, 18 Oct 2011)*
This was the second release candidate of the 2.5 series.
Version 2.5.0 rc1
-----------------
......
......@@ -2,7 +2,7 @@
m4_define([gnt_version_major], [2])
m4_define([gnt_version_minor], [5])
m4_define([gnt_version_revision], [0])
m4_define([gnt_version_suffix], [~rc2])
m4_define([gnt_version_suffix], [~rc4])
m4_define([gnt_version_full],
m4_format([%d.%d.%d%s],
gnt_version_major, gnt_version_minor,
......
#!/bin/sh
# ganeti node daemon starter script
# ganeti daemons init script
# based on skeleton from Debian GNU/Linux
### BEGIN INIT INFO
# Provides: ganeti
......
......@@ -98,7 +98,7 @@ The scripts will be run as follows:
- stdout and stderr are directed to files
- PATH is reset to ``/sbin:/bin:/usr/sbin:/usr/bin``
- PATH is reset to :pyeval:`constants.HOOKS_PATH`
- the environment is cleared, and only ganeti-specific variables will
be left
......
......@@ -1298,6 +1298,10 @@ The query arguments used up to and including Ganeti 2.4 are deprecated
and should no longer be used. The new request format can be detected by
the presence of the :pyeval:`rlib2._NODE_MIGRATE_REQV1` feature string.
Job result:
.. opcode_result:: OP_NODE_MIGRATE
``/2/nodes/[node_name]/role``
+++++++++++++++++++++++++++++
......
......@@ -315,11 +315,14 @@ checkData nl il =
- nodeIdsk node il
newn = Node.setFmem (Node.setXmem node delta_mem)
(Node.fMem node - adj_mem)
umsg1 = [printf "node %s is missing %d MB ram \
\and %d GB disk"
nname delta_mem (delta_dsk `div` 1024) |
delta_mem > 512 || delta_dsk > 1024]::[String]
in (msgs ++ umsg1, newn)
umsg1 =
if delta_mem > 512 || delta_dsk > 1024
then (printf "node %s is missing %d MB ram \
\and %d GB disk"
nname delta_mem (delta_dsk `div` 1024)):
msgs
else msgs
in (umsg1, newn)
) [] nl
-- | Compute the amount of memory used by primary instances on a node.
......
......@@ -280,10 +280,9 @@ selectGroup opts gl nlf ilf = do
Just grp ->
case lookup (Group.idx grp) ngroups of
Nothing -> do
-- TODO: while this is unlikely to happen, log here the
-- actual group data to help debugging
hPutStrLn stderr "Internal failure, missing group idx"
exitWith $ ExitFailure 1
-- This will only happen if there are no nodes assigned
-- to this group
return (Group.name grp, (Container.empty, Container.empty))
Just cdata -> return (Group.name grp, cdata)
-- | Do a few checks on the cluster data.
......
......@@ -1400,7 +1400,7 @@ commands = {
"", "Does a check on the cluster disk status"),
"repair-disk-sizes": (
RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
"", "Updates mismatches in recorded disk sizes"),
"[instance...]", "Updates mismatches in recorded disk sizes"),
"master-failover": (
MasterFailover, ARGS_NONE, [NOVOTING_OPT],
"", "Makes the current node the master"),
......
......@@ -3243,7 +3243,10 @@ class LUClusterRepairDiskSizes(NoHooksLU):
locking.LEVEL_NODE_RES: locking.ALL_SET,
locking.LEVEL_INSTANCE: locking.ALL_SET,
}
self.share_locks = _ShareAll()
self.share_locks = {
locking.LEVEL_NODE: 1,
locking.LEVEL_INSTANCE: 0,
}
def DeclareLocks(self, level):
if level == locking.LEVEL_NODE_RES and self.wanted_names is not None:
......@@ -6674,7 +6677,7 @@ class LUInstanceRename(LogicalUnit):
new_name = self.op.new_name
if self.op.name_check:
hostname = netutils.GetHostname(name=new_name)
if hostname != new_name:
if hostname.name != new_name:
self.LogInfo("Resolved given name '%s' to '%s'", new_name,
hostname.name)
if not utils.MatchNameComponent(self.op.new_name, [hostname.name]):
......@@ -8284,6 +8287,11 @@ def _RemoveDisks(lu, instance, target_node=None):
" continuing anyway: %s", device.iv_name, node, msg)
all_result = False
# if this is a DRBD disk, return its port to the pool
if device.dev_type in constants.LDS_DRBD:
tcp_port = device.logical_id[2]
lu.cfg.AddTcpUdpPort(tcp_port)
if instance.disk_template == constants.DT_FILE:
file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
if target_node:
......@@ -9102,6 +9110,11 @@ class LUInstanceCreate(LogicalUnit):
if self.op.iallocator is not None:
self._RunAllocator()
# Release all unneeded node locks
_ReleaseLocks(self, locking.LEVEL_NODE,
keep=filter(None, [self.op.pnode, self.op.snode,
self.op.src_node]))
#### node related checks
# check primary node
......@@ -10658,9 +10671,10 @@ def _LoadNodeEvacResult(lu, alloc_result, early_release, use_nodes):
(moved, failed, jobs) = alloc_result
if failed:
lu.LogWarning("Unable to evacuate instances %s",
utils.CommaJoin("%s (%s)" % (name, reason)
for (name, reason) in failed))
failreason = utils.CommaJoin("%s (%s)" % (name, reason)
for (name, reason) in failed)
lu.LogWarning("Unable to evacuate instances %s", failreason)
raise errors.OpExecError("Unable to evacuate instances %s" % failreason)
if moved:
lu.LogInfo("Instances to be moved: %s",
......@@ -11566,6 +11580,11 @@ class LUInstanceSetParams(LogicalUnit):
self.LogWarning("Could not remove metadata for disk %d on node %s,"
" continuing anyway: %s", idx, pnode, msg)
# this is a DRBD disk, return its port to the pool
for disk in old_disks:
tcp_port = disk.logical_id[2]
self.cfg.AddTcpUdpPort(tcp_port)
# Node resource locks will be released by caller
def Exec(self, feedback_fn):
......@@ -11598,6 +11617,11 @@ class LUInstanceSetParams(LogicalUnit):
self.LogWarning("Could not remove disk/%d on node %s: %s,"
" continuing anyway", device_idx, node, msg)
result.append(("disk/%d" % device_idx, "remove"))
# if this is a DRBD disk, return its port to the pool
if device.dev_type in constants.LDS_DRBD:
tcp_port = device.logical_id[2]
self.cfg.AddTcpUdpPort(tcp_port)
elif disk_op == constants.DDM_ADD:
# add a new disk
if instance.disk_template in (constants.DT_FILE,
......
......@@ -45,11 +45,10 @@ except ImportError:
# modules (hmac, for example) which have changed their behavior as well from
# one version to the other.
try:
# pylint: disable=F0401
# Yes, these don't always exist, that's why we're testing
# Yes, we're not using the imports in this module.
# pylint: disable=W0611
from hashlib import md5 as md5_hash
from hashlib import sha1 as sha1_hash
from hashlib import md5 as md5_hash # pylint: disable=W0611,E0611,F0401
from hashlib import sha1 as sha1_hash # pylint: disable=W0611,E0611,F0401
# this additional version is needed for compatibility with the hmac module
sha1 = sha1_hash
except ImportError:
......
......@@ -1209,6 +1209,14 @@ class ConfigWriter:
"""
if instance_name not in self._config_data.instances:
raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
# If a network port has been allocated to the instance,
# return it to the pool of free ports.
inst = self._config_data.instances[instance_name]
network_port = getattr(inst, "network_port", None)
if network_port is not None:
self._config_data.cluster.tcpudp_port_pool.add(network_port)
del self._config_data.instances[instance_name]
self._config_data.cluster.serial_no += 1
self._WriteConfig()
......
......@@ -366,6 +366,7 @@ HOOKS_PHASE_POST = "post"
HOOKS_NAME_CFGUPDATE = "config-update"
HOOKS_NAME_WATCHER = "watcher"
HOOKS_VERSION = 2
HOOKS_PATH = "/sbin:/bin:/usr/sbin:/usr/bin"
# hooks subject type (what object type does the LU deal with)
HTYPE_CLUSTER = "CLUSTER"
......
......@@ -1827,7 +1827,8 @@ class JobQueue(object):
@return: a string representing the job identifier.
"""
assert count > 0
assert ht.TPositiveInt(count)
# New number
serial = self._last_serial + count
......
......@@ -560,7 +560,7 @@ class HooksMaster(object):
"""
env = {
"PATH": "/sbin:/bin:/usr/sbin:/usr/bin",
"PATH": constants.HOOKS_PATH,
"GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
"GANETI_OP_CODE": self.opcode,
"GANETI_DATA_DIR": constants.DATA_DIR,
......
......@@ -1025,6 +1025,7 @@ class OpNodeMigrate(OpCode):
("iallocator", None, ht.TMaybeString,
"Iallocator for deciding the target node for shared-storage instances"),
]
OP_RESULT = TJobIdListOnly
class OpNodeEvacuate(OpCode):
......
......@@ -28,6 +28,7 @@ import time
import tempfile
import shutil
import operator
import itertools
from ganeti import constants
from ganeti import mcpu
......@@ -380,5 +381,71 @@ class TestClusterVerifyFiles(unittest.TestCase):
]))
class _FakeLU:
def __init__(self):
self.warning_log = []
self.info_log = []
def LogWarning(self, text, *args):
self.warning_log.append((text, args))
def LogInfo(self, text, *args):
self.info_log.append((text, args))
class TestLoadNodeEvacResult(unittest.TestCase):
def testSuccess(self):
for moved in [[], [
("inst20153.example.com", "grp2", ["nodeA4509", "nodeB2912"]),
]]:
for early_release in [False, True]:
for use_nodes in [False, True]:
jobs = [
[opcodes.OpInstanceReplaceDisks().__getstate__()],
[opcodes.OpInstanceMigrate().__getstate__()],
]
alloc_result = (moved, [], jobs)
assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
lu = _FakeLU()
result = cmdlib._LoadNodeEvacResult(lu, alloc_result,
early_release, use_nodes)
if moved:
(_, (info_args, )) = lu.info_log.pop(0)
for (instname, instgroup, instnodes) in moved:
self.assertTrue(instname in info_args)
if use_nodes:
for i in instnodes:
self.assertTrue(i in info_args)
else:
self.assertTrue(instgroup in info_args)
self.assertFalse(lu.info_log)
self.assertFalse(lu.warning_log)
for op in itertools.chain(*result):
if hasattr(op.__class__, "early_release"):
self.assertEqual(op.early_release, early_release)
else:
self.assertFalse(hasattr(op, "early_release"))
def testFailed(self):
alloc_result = ([], [
("inst5191.example.com", "errormsg21178"),
], [])
assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
lu = _FakeLU()
self.assertRaises(errors.OpExecError, cmdlib._LoadNodeEvacResult,
lu, alloc_result, False, False)
self.assertFalse(lu.info_log)
(_, (args, )) = lu.warning_log.pop(0)
self.assertTrue("inst5191.example.com" in args)
self.assertTrue("errormsg21178" in args)
self.assertFalse(lu.warning_log)
if __name__ == "__main__":
testutils.GanetiTestProgram()
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