Commit acd9ff9e authored by Iustin Pop's avatar Iustin Pop
Browse files

Introduce an RPC call for OS parameters validation



While we only support the 'parameters' check today, the RPC call is
generic enough that will be able to support other checks in the future.
The backend function will both validate the parameters list (so as to
make sure we don't pass in extra parameters that the OS validation
doesn't care about) and the parameter values, via the OS verify script.
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent c7d04a6b
......@@ -712,6 +712,14 @@ class NodeHttpServer(http.server.HttpServer):
os_obj = backend.OSFromDisk(name)
return os_obj.ToDict()
@staticmethod
def perspective_os_validate(params):
"""Run a given OS' validation routine.
"""
required, name, checks, params = params
return backend.ValidateOS(required, name, checks, params)
# hooks -----------------------
@staticmethod
......
......@@ -2457,6 +2457,67 @@ def ValidateHVParams(hvname, hvparams):
_Fail(str(err), log=False)
def _CheckOSPList(os_obj, parameters):
"""Check whether a list of parameters is supported by the OS.
@type os_obj: L{objects.OS}
@param os_obj: OS object to check
@type parameters: list
@param parameters: the list of parameters to check
"""
supported = [v[0] for v in os_obj.supported_parameters]
delta = frozenset(parameters).difference(supported)
if delta:
_Fail("The following parameters are not supported"
" by the OS %s: %s" % (os_obj.name, utils.CommaJoin(delta)))
def ValidateOS(required, osname, checks, osparams):
"""Validate the given OS' parameters.
@type required: boolean
@param required: whether absence of the OS should translate into
failure or not
@type osname: string
@param osname: the OS to be validated
@type checks: list
@param checks: list of the checks to run (currently only 'parameters')
@type osparams: dict
@param osparams: dictionary with OS parameters
@rtype: boolean
@return: True if the validation passed, or False if the OS was not
found and L{required} was false
"""
if not constants.OS_VALIDATE_CALLS.issuperset(checks):
_Fail("Unknown checks required for OS %s: %s", osname,
set(checks).difference(constants.OS_VALIDATE_CALLS))
name_only = osname.split("+", 1)[0]
status, tbv = _TryOSFromDisk(name_only, None)
if not status:
if required:
_Fail(tbv)
else:
return False
if constants.OS_VALIDATE_PARAMETERS in checks:
_CheckOSPList(tbv, osparams.keys())
validate_env = OSCoreEnv(tbv, osparams)
result = utils.RunCmd([tbv.verify_script] + checks, env=validate_env,
cwd=tbv.path)
if result.failed:
logging.error("os validate command '%s' returned error: %s output: %s",
result.cmd, result.fail_reason, result.output)
_Fail("OS validation script failed (%s), output: %s",
result.fail_reason, result.output, log=False)
return True
def DemoteFromMC():
"""Demotes the current node from master candidate role.
......
......@@ -6091,6 +6091,35 @@ def _CheckHVParams(lu, nodenames, hvname, hvparams):
info.Raise("Hypervisor parameter validation failed on node %s" % node)
def _CheckOSParams(lu, required, nodenames, osname, osparams):
"""OS parameters validation.
@type lu: L{LogicalUnit}
@param lu: the logical unit for which we check
@type required: boolean
@param required: whether the validation should fail if the OS is not
found
@type nodenames: list
@param nodenames: the list of nodes on which we should check
@type osname: string
@param osname: the name of the hypervisor we should use
@type osparams: dict
@param osparams: the parameters which we need to check
@raise errors.OpPrereqError: if the parameters are not valid
"""
result = lu.rpc.call_os_validate(required, nodenames, osname,
[constants.OS_VALIDATE_PARAMETERS],
osparams)
for node, nres in result.items():
# we don't check for offline cases since this should be run only
# against the master node and/or an instance's nodes
nres.Raise("OS Parameters validation failed on node %s" % node)
if not nres.payload:
lu.LogInfo("OS %s not found on node %s, validation skipped",
osname, node)
class LUCreateInstance(LogicalUnit):
"""Create an instance.
......
......@@ -459,6 +459,7 @@ OS_VARIANTS_FILE = 'variants.list'
OS_PARAMETERS_FILE = 'parameters.list'
OS_VALIDATE_PARAMETERS = 'parameters'
OS_VALIDATE_CALLS = frozenset([OS_VALIDATE_PARAMETERS])
# ssh constants
SSH_CONFIG_DIR = _autoconf.SSH_CONFIG_DIR
......
......@@ -1046,6 +1046,16 @@ class RpcRunner(object):
result.payload = objects.OS.FromDict(result.payload)
return result
@_RpcTimeout(_TMO_FAST)
def call_os_validate(self, required, nodes, name, checks, params):
"""Run a validation routine for a given OS.
This is a multi-node call.
"""
return self._MultiNodeCall(nodes, "os_validate",
[required, name, checks, params])
@_RpcTimeout(_TMO_NORMAL)
def call_hooks_runner(self, node_list, hpath, phase, env):
"""Call the hooks runner.
......
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