Commit 410945f1 authored by Klaus Aehlig's avatar Klaus Aehlig

Merge branch 'stable-2.9' into stable-2.10

* stable-2.9
  Revision bump for 2.9.3
  Schedule 2.9.3 release
  Document fix of issue 691 in NEWS
  NEWS: fix typo in 2.8.4 release
  Fix 'hvparams' of '_InstanceStartupMemory' on hypervisors
  Add missing option to gnt-instance documentation
  Update NEWS file
  Fix disk_type error in hypervisor parameter documentation
  Update NEWS file: issue 687 and configure fix
  luxid: fix detection of master node in node query
  query: fix detection of master in _GetNodeRole()
  Break line longer than 80 chars in configure.ac
  Technical writing: improve documentation and glossary
  configure: allow detection of Sphinx 1.2+
  Remove deprecated _ERROR_DATA_KEY in QMP
  Technical writing: improve main documentation page
  Update the NEWS file with the Issue 640 fix
  Ensure that all the hypervisors exist in the config file
  Fix testEncodeInstance test input

* stable-2.8
  Version bump for 2.8.4 and NEWS update
  Update NEWS file with news about job cancellation bugfix
  Fix QA flakiness
  Linting fix: remove unused import
  Add missing parameter entry to man file
  Add QA test for job cancellation
  Add correct locking of master node to gnt-debug delay
  Add job id type assert to jqueue.py
  Add job id transformation/check to Luxi Python client
  Start-master/stop-master always fail if confd is disabled
  Improve backwards compatibility of Issue 649 fix
  Add missing NEWS entries from stable-2.8
  Change usb_devices separator to whitespace
  Add support for blktap2 file-driver
  Update opcodes test to include network tags
  Make network tags searchable
  Add network tag tests to QA
  Fix RAPI network tag handling
  Fix gnt-network list-tags

Conflicts:
	NEWS
	configure.ac
	doc/index.rst
	lib/constants.py
	lib/hypervisor/hv_kvm.py
	src/Ganeti/OpParams.hs
	src/Ganeti/Query/Server.hs
	test/hs/Test/Ganeti/OpCodes.hs
	test/py/ganeti.hypervisor.hv_xen_unittest.py
	test/py/ganeti.rpc_unittest.py
Resolution:
	NEWS: take both additions
	configure.ac: ignore revision bump
	doc/index.rst: take stable-2.9 changes
	lib/constants.py: ignore stable-2.9 changes, but redo
	    7bc2c097 in the new constants framework
	(rest trivial)
Signed-off-by: default avatarKlaus Aehlig <aehlig@google.com>
Reviewed-by: default avatarHrvoje Ribicic <riba@google.com>
parents 16b85a3c 8dba1797
......@@ -129,6 +129,29 @@ before rc1.
- Issue 623: IPv6 Masterd <-> Luxid communication error
Version 2.9.3
-------------
*(Released Mon, 27 Jan 2014)*
- Ensure that all the hypervisors exist in the config file (Issue 640)
- Correctly recognise the role as master node (Issue 687)
- configure: allow detection of Sphinx 1.2+ (Issue 502)
- gnt-instance now honors the KVM path correctly (Issue 691)
Inherited from the 2.8 branch:
- Change the list separator for the usb_devices parameter from comma to space.
Commas could not work because they are already the hypervisor option
separator (Issue 649)
- Add support for blktap2 file-driver (Issue 638)
- Add network tag definitions to the haskell codebase (Issue 641)
- Fix RAPI network tag handling
- Add the network tags to the tags searched by gnt-cluster search-tags
- Fix caching bug preventing jobs from being cancelled
- Start-master/stop-master was always failing if ConfD was disabled. (Issue 685)
Version 2.9.2
-------------
......@@ -297,6 +320,22 @@ This was the first beta release of the 2.9 series. All important changes
are listed in the latest 2.9 entry.
Version 2.8.4
-------------
*(Released Thu, 23 Jan 2014)*
- Change the list separator for the usb_devices parameter from comma to space.
Commas could not work because they are already the hypervisor option
separator (Issue 649)
- Add support for blktap2 file-driver (Issue 638)
- Add network tag definitions to the haskell codebase (Issue 641)
- Fix RAPI network tag handling
- Add the network tags to the tags searched by gnt-cluster search-tags
- Fix caching bug preventing jobs from being cancelled
- Start-master/stop-master was always failing if ConfD was disabled. (Issue 685)
Version 2.8.3
-------------
......
......@@ -397,7 +397,8 @@ else
# Note: Character classes ([...]) need to be double quoted due to autoconf
# using m4
elif ! echo "$sphinxver" | grep -q -E '^Sphinx[[[:space:]]]+v[[1-9]]\>'; then
elif ! echo "$sphinxver" | grep -q -E \
'^Sphinx[[[:space:]]]+(\(sphinx-build\)[[[:space:]]]+|v)[[1-9]]\>'; then
AC_MSG_ERROR([Sphinx 1.0 or higher is required])
fi
fi
......
......@@ -292,14 +292,20 @@ check_and_start() {
start_master() {
start ganeti-masterd
start ganeti-rapi
_confd_enabled && start ganeti-luxid
if _confd_enabled; then
start ganeti-luxid
else
return 0
fi
}
# Stops the master role
stop_master() {
if _confd_enabled ; then
stop ganeti-luxid
fi
stop ganeti-rapi
stop ganeti-masterd
_confd_enabled && stop ganeti-luxid
}
# Start all daemons
......
......@@ -5,3 +5,7 @@ a.external {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs%2B9AAAAVklEQVR4Xn3PgQkAMQhDUXfqTu7kTtkpd5RA8AInfArtQ2iRXFWT2QedAfttj2FsPIOE1eCOlEuoWWjgzYaB%2FIkeGOrxXhqB%2BuA9Bfcm0lAZuh%2BYIeAD%2BcAqSz4kCMUAAAAASUVORK5CYII%3D") no-repeat scroll right center transparent;
padding-right: 13px;
}
a {
text-decoration: underline;
}
......@@ -8,78 +8,73 @@ Glossary
:sorted:
ballooning
A term describing runtime, dynamic changes to an instance's memory,
without having to reboot the instance. Depending on the hypervisor
and configuration, the changes need to be initiated manually, or
they can be automatically initiated by the hypervisor based on the
node and instances memory usage.
A term describing dynamic changes to an instance's memory while the instance
is running that don't require an instance reboot. Depending on the
hypervisor and configuration, changes may be automatically initiated by the
hypervisor (based on the memory usage of the node and instance), or may need
to be initiated manually.
BE parameter
BE stands for *backend*. BE parameters are hypervisor-independent
instance parameters such as the amount of RAM/virtual CPUs it has
been allocated.
BE stands for *backend*. BE parameters are hypervisor-independent instance
parameters, such as the amount of RAM/virtual CPUs allocated to an instance.
DRBD
A block device driver that can be used to build RAID1 across the
network or even shared storage, while using only locally-attached
storage.
A block device driver that can be used to build RAID1 across the network or
across shared storage, while using only locally-attached storage.
HV parameter
HV stands for *hypervisor*. HV parameters are the ones that describe
the virtualization-specific aspects of the instance; for example,
what kernel to use to boot the instance (if any), or what emulation
model to use for the emulated hard drives.
HV stands for *hypervisor*. HV parameters describe the virtualization-
specific aspects of the instance. For example, a HV parameter might describe
what kernel (if any) to use to boot the instance or what emulation model to
use for the emulated hard drives.
HVM
Hardware virtualization mode, where the virtual machine is oblivious
to the fact that's being virtualized and all the hardware is
*Hardware Virtualization Mode*. In this mode, the virtual machine is
oblivious to the fact that it is virtualized and all its hardware is
emulated.
LogicalUnit
The code associated with an :term:`OpCode`, e.g. the code that
The code associated with an :term:`OpCode`; for example, the code that
implements the startup of an instance.
LUXI
Local UniX Interface. The IPC method over :manpage:`unix(7)`
sockets used between the CLI tools/RAPI daemon and the master
daemon.
Local UniX Interface. The IPC method over :manpage:`unix(7)` sockets used
between the CLI tools/RAPI daemon and the master daemon.
OOB
*Out of Band*. This term describes methods of accessing a machine
(or parts of a machine) not via the usual network connection. For
example, accessing a remote server via a physical serial console or
via a virtual one IPMI counts as out of band access.
*Out of Band*. This term describes methods of accessing a machine (or parts
of a machine) by means other than the usual network connection. Examples
include accessing a remote server via a physical serial console or via a
virtual console. IPMI is also considered OOB access.
OpCode
A data structure encapsulating a basic cluster operation; for
example, start instance, add instance, etc.
A data structure encapsulating a basic cluster operation; for example: start
instance, add instance, etc.
PVM
(Xen) Para-virtualization mode, where the virtual machine knows it's
being virtualized and as such there is no need for hardware
emulation or virtualization.
(Xen) *Para-virtualization mode*. In this mode, the virtual machine is aware
that it is virtualized; therefore, there is no need for hardware emulation
or virtualization.
SoR
*State of Record*. Refers to values/properties that come from an
authoritative configuration source. For example, the maximum VCPU
over-subscription ratio is a *SoR* value, but the current
over-subscription ration (based on how many instances live on the
node) is a :term:`SoW` value.
authoritative configuration source. For example, the maximum VCPU over-
subscription ratio is a SoR value, but the current over-subscription ratio
(based upon how many instances live on the node) is a :term:`SoW` value.
SoW
*State of the World*. Refers to values that describe directly the
world, as opposed to values that come from the
configuration. Contrast with :term:`SoR`.
*State of the World*. Refers to values that directly describe the world, as
opposed to values that come from the configuration (which are considered
:term:`SoR`).
tmem
Xen Transcendent Memory
(http://en.wikipedia.org/wiki/Transcendent_memory). It is a
mechanism used by Xen to provide memory over-subscription.
Xen Transcendent Memory (http://en.wikipedia.org/wiki/Transcendent_memory).
tmem is a mechanism used by Xen to provide memory over-subscription.
watcher
:command:`ganeti-watcher` is a tool that should be run regularly
from cron and takes care of restarting failed instances, restarting
secondary DRBD devices, etc. For more details, see the man page
:command:`ganeti-watcher` is a tool that should be run regularly from
cron. The tool executes tasks such as restarting failed instances and
restarting secondary DRBD devices. For more details, see the man page
:manpage:`ganeti-watcher(8)`.
......
......@@ -4,82 +4,63 @@
Welcome to Ganeti's documentation!
==================================
This page is the starting point for browsing the ganeti documentation. It
contains link to all the sections of the documentation, grouped by topic.
This page is the starting point for browsing the Ganeti
documentation. Below, the corpus of Ganeti documentation is grouped by
topic.
The list of changes between Ganeti versions is provided in the :doc:`news` file.
A few quick references:
In order to help understanding the Ganeti terminology, a :doc:`glossary` is
provided.
Also see the :ref:`search`.
- :doc:`glossary`: Provides explanations of basic Ganeti terminology.
- :doc:`news` file: Lists changes between Ganeti versions.
- :ref:`search`: Allows you to search for key terms across Ganeti documentation.
Installing Ganeti
+++++++++++++++++
In order to install Ganeti, follow the instructions contained in the
:doc:`install`.
If you are an experienced user, the content of the :doc:`install-quick` should
be enough.
Use the following resources to install and/or upgrade Ganeti:
Instructions for upgrading an existing installation to the latest version of
Ganeti are contained in the :doc:`upgrade`.
- :doc:`install`: Comprehensive instructions for installing Ganeti.
- :doc:`install-quick`: A shortened installation guide for the experienced Ganeti user.
- :doc:`upgrade`: Instructions for upgrading an existing Ganeti installation to the latest version.
Using Ganeti
++++++++++++
Information about how to manage a Ganeti cluster after it has been installed
(including management of nodes, instances, info about the tools and the
monitoring agent) can be found in :doc:`admin`.
A more example-oriended guide is available in :doc:`walkthrough`.
The various tool that are part of Ganeti are described one by one in the
:doc:`manpages`.
A description of the security model underlying a Ganeti cluster can be found in
the :doc:`security` document.
Ganeti functionalities can be extended by hooking scripts automatically
activated when certain events happen. Information on this mechanism is provided
in the :doc:`hooks` document.
The following resources provide guidance on how to use Ganeti:
While using Ganeti, the allocation of instances can happen manually or
automatically, through some external tools making decisions about this. The API
for such tools is described in :doc:`iallocator`.
- :doc:`admin`: Information about how to manage a Ganeti cluster after it is installed (including management of nodes and instances, and information about Ganeti's tools and monitoring agent).
- :doc:`walkthrough`: An example-oriented guide to Ganeti.
- :doc:`manpages`: Descriptions of the various tools that are part of Ganeti.
- :doc:`security`: A description of the security model underlying a Ganeti cluster.
- :doc:`hooks`: Information on hooking scripts, which extend Ganeti functionalities by automatically activating when certain events occur.
- :doc:`iallocator`: Description of the API for external tools, which can allocate instances either manually or automatically.
- :doc:`rapi`: Description of the Ganeti remote API, which allows programmatic access to most of the functionalities of Ganeti.
- :doc:`ovfconverter`: Description of a tool that provides compatibility with the standard OVF virtual machine interchange format.
- :doc:`virtual-cluster`: Explanation of how to use virtual cluster support, which is utilized mainly for testing reasons.
Most of the functionalities of Ganeti can be programmatically accessed through
an API, the :doc:`rapi`.
Some features are explicitly targeted for large Ganeti installations,
in which multiple clusters are present:
Compatibility with the standard OVF virtual machine interchange format is
provided by the :doc:`ovfconverter`.
Mainly for testing reasons, Ganeti also has :doc:`virtual-cluster`.
A few functionalities are explicitly targeted for big installations, where
multiple clusters are present. A tool for merging two existing clusters
is provided, and is described in :doc:`cluster-merge`. There is also a document
describing the procedure for :doc:`move-instance`.
- :doc:`cluster-merge`: Describes a tool for merging two existing clusters.
- :doc:`move-instance`: Describes how to move instances between clusters.
Developing Ganeti
+++++++++++++++++
A few documents useful for who wants to modify Ganeti are available and listed
in this section.
A description of the locking strategy and, in particular, lock order
dependencies is presented in :doc:`locking`.
There are a few documents particularly useful for developers who want
to modify Ganeti:
Build dependencies and other useful development-related information
are provided in the :doc:`devnotes`.
- :doc:`locking`: Describes Ganeti's locking strategy and lock order dependencies.
- :doc:`devnotes`: Details build dependencies and other useful development-related information.
All the features implemented in Ganeti are described in a design document before
being actually implemented. Designs can be implemented in a released version, or
be still draft (and therefore either incomplete or not implemented).
Implemented designs
-------------------
Before actual implementation, all Ganeti features are described in a
design document. Designs fall into two categories: released versions
and draft versions (which are either incomplete or not implemented).
.. toctree::
:maxdepth: 1
......
......@@ -288,6 +288,7 @@ __all__ = [
"OPT_COMPL_ONE_OS",
"OPT_COMPL_ONE_EXTSTORAGE",
"cli_option",
"FixHvParams",
"SplitNodeOption",
"CalculateOSNames",
"ParseFields",
......@@ -2618,6 +2619,21 @@ def ParseNicOption(optvalue):
return nics
def FixHvParams(hvparams):
# In Ganeti 2.8.4 the separator for the usb_devices hvparam was changed from
# comma to space because commas cannot be accepted on the command line
# (they already act as the separator between different hvparams). Still,
# RAPI should be able to accept commas for backwards compatibility.
# Therefore, we convert spaces into commas here, and we keep the old
# parsing logic everywhere else.
try:
new_usb_devices = hvparams[constants.HV_USB_DEVICES].replace(" ", ",")
hvparams[constants.HV_USB_DEVICES] = new_usb_devices
except KeyError:
#No usb_devices, no modification required
pass
def GenericInstanceCreate(mode, opts, args):
"""Add an instance to the cluster via either creation or import.
......@@ -2710,6 +2726,7 @@ def GenericInstanceCreate(mode, opts, args):
utils.ForceDictType(opts.beparams, constants.BES_PARAMETER_COMPAT)
utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
FixHvParams(hvparams)
if mode == constants.INSTANCE_CREATE:
start = opts.start
......
......@@ -1312,6 +1312,7 @@ def SetInstanceParams(opts, args):
utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES,
allowed_values=[constants.VALUE_DEFAULT])
FixHvParams(opts.hvparams)
nics = _ConvertNicDiskModifications(opts.nics)
for action, _, __ in nics:
......
......@@ -130,17 +130,26 @@ class LUTagsSearch(NoHooksLU):
raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
(self.op.pattern, err), errors.ECODE_INVAL)
@staticmethod
def _ExtendTagTargets(targets, object_type_name, object_info_dict):
return targets.extend(("/%s/%s" % (object_type_name, o.name), o)
for o in object_info_dict.values())
def Exec(self, feedback_fn):
"""Returns the tag list.
"""
tgts = [("/cluster", self.cfg.GetClusterInfo())]
ilist = self.cfg.GetAllInstancesInfo().values()
tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
nlist = self.cfg.GetAllNodesInfo().values()
tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
tgts.extend(("/nodegroup/%s" % n.name, n)
for n in self.cfg.GetAllNodeGroupsInfo().values())
LUTagsSearch._ExtendTagTargets(tgts, "instances",
self.cfg.GetAllInstancesInfo())
LUTagsSearch._ExtendTagTargets(tgts, "nodes",
self.cfg.GetAllNodesInfo())
LUTagsSearch._ExtendTagTargets(tgts, "nodegroup",
self.cfg.GetAllNodeGroupsInfo())
LUTagsSearch._ExtendTagTargets(tgts, "network",
self.cfg.GetAllNetworksInfo())
results = []
for path, target in tgts:
for tag in target.GetTags():
......
#
#
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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
......@@ -53,13 +53,21 @@ class LUTestDelay(NoHooksLU):
"""
self.needed_locks = {}
if self.op.on_nodes or self.op.on_master:
self.needed_locks[locking.LEVEL_NODE] = []
if self.op.on_nodes:
# _GetWantedNodes can be used here, but is not always appropriate to use
# this way in ExpandNames. Check LogicalUnit.ExpandNames docstring for
# more information.
(self.op.on_node_uuids, self.op.on_nodes) = \
GetWantedNodes(self, self.op.on_nodes)
self.needed_locks[locking.LEVEL_NODE] = self.op.on_node_uuids
self.needed_locks[locking.LEVEL_NODE].extend(self.op.on_node_uuids)
if self.op.on_master:
# The node lock should be acquired for the master as well.
self.needed_locks[locking.LEVEL_NODE].append(self.cfg.GetMasterNode())
def _TestDelay(self):
"""Do the actual sleep.
......
......@@ -381,7 +381,7 @@ class BaseHypervisor(object):
"""
raise NotImplementedError
def _InstanceStartupMemory(self, instance, hvparams=None):
def _InstanceStartupMemory(self, instance):
"""Get the correct startup memory for an instance
This function calculates how much memory an instance should be started
......@@ -394,7 +394,7 @@ class BaseHypervisor(object):
@return: memory the instance should be started with
"""
free_memory = self.GetNodeInfo(hvparams=hvparams)["memory_free"]
free_memory = self.GetNodeInfo(hvparams=instance.hvparams)["memory_free"]
max_start_mem = min(instance.beparams[constants.BE_MAXMEM], free_memory)
start_mem = max(instance.beparams[constants.BE_MINMEM], max_start_mem)
return start_mem
......
......@@ -462,7 +462,6 @@ class QmpConnection(MonitorSocket):
_RETURN_KEY = RETURN_KEY = "return"
_ACTUAL_KEY = ACTUAL_KEY = "actual"
_ERROR_CLASS_KEY = "class"
_ERROR_DATA_KEY = "data"
_ERROR_DESC_KEY = "desc"
_EXECUTE_KEY = "execute"
_ARGUMENTS_KEY = "arguments"
......@@ -606,11 +605,10 @@ class QmpConnection(MonitorSocket):
err = response[self._ERROR_KEY]
if err:
raise errors.HypervisorError("kvm: error executing the %s"
" command: %s (%s, %s):" %
" command: %s (%s):" %
(command,
err[self._ERROR_DESC_KEY],
err[self._ERROR_CLASS_KEY],
err[self._ERROR_DATA_KEY]))
err[self._ERROR_CLASS_KEY]))
elif not response[self._EVENT_KEY]:
return response
......
......@@ -48,6 +48,7 @@ _DISK_LETTERS = string.ascii_lowercase
_FILE_DRIVER_MAP = {
constants.FD_LOOP: "file",
constants.FD_BLKTAP: "tap:aio",
constants.FD_BLKTAP2: "tap2:tapdisk:aio",
}
......@@ -593,8 +594,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
"""Start an instance.
"""
startup_memory = self._InstanceStartupMemory(instance,
hvparams=instance.hvparams)
startup_memory = self._InstanceStartupMemory(instance)
self._MakeConfigFile(instance, startup_memory, block_devices)
......
#
#
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 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
......@@ -2044,6 +2044,8 @@ class JobQueue(object):
@return: either None or the job object
"""
assert isinstance(job_id, int), "Job queue: Supplied job id is not an int!"
job = self._memcache.get(job_id, None)
if job:
logging.debug("Found job %s in memcache", job_id)
......
#
#
# Copyright (C) 2006, 2007, 2011, 2012 Google Inc.
# Copyright (C) 2006, 2007, 2011, 2012, 2014 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
......@@ -466,13 +466,25 @@ class Client(object):
jobs_state.append([op.__getstate__() for op in ops])
return self.CallMethod(REQ_SUBMIT_MANY_JOBS, (jobs_state, ))
@staticmethod
def _PrepareJobId(request_name, job_id):
try:
return int(job_id)
except ValueError:
raise RequestError("Invalid parameter passed to %s as job id: "
" expected integer, got value %s" %
(request_name, job_id))
def CancelJob(self, job_id):
job_id = Client._PrepareJobId(REQ_CANCEL_JOB, job_id)
return self.CallMethod(REQ_CANCEL_JOB, (job_id, ))
def ArchiveJob(self, job_id):
job_id = Client._PrepareJobId(REQ_ARCHIVE_JOB, job_id)
return self.CallMethod(REQ_ARCHIVE_JOB, (job_id, ))
def ChangeJobPriority(self, job_id, priority):
job_id = Client._PrepareJobId(REQ_CHANGE_JOB_PRIORITY, job_id)
return self.CallMethod(REQ_CHANGE_JOB_PRIORITY, (job_id, priority))
def AutoArchiveJobs(self, age):
......@@ -503,6 +515,7 @@ class Client(object):
min(WFJC_TIMEOUT, timeout)))
def WaitForJobChange(self, job_id, fields, prev_job_info, prev_log_serial):
job_id = Client._PrepareJobId(REQ_WAIT_FOR_JOB_CHANGE, job_id)
while True:
result = self.WaitForJobChangeOnce(job_id, fields,
prev_job_info, prev_log_serial)
......
......@@ -1598,9 +1598,13 @@ class Cluster(TaggableObject):
if self.hvparams is None:
self.hvparams = constants.HVC_DEFAULTS
else:
for hypervisor in self.hvparams:
for hypervisor in constants.HYPER_TYPES:
try:
existing_params = self.hvparams[hypervisor]
except KeyError:
existing_params = {}
self.hvparams[hypervisor] = FillDict(
constants.HVC_DEFAULTS[hypervisor], self.hvparams[hypervisor])
constants.HVC_DEFAULTS[hypervisor], existing_params)
if self.os_hvp is None:
self.os_hvp = {}
......
......@@ -946,16 +946,16 @@ def _StaticValue(value):
return compat.partial(_StaticValueInner, value)
def _GetNodeRole(node, master_name):
def _GetNodeRole(node, master_uuid):
"""Determine node role.
@type node: L{objects.Node}
@param node: Node object
@type master_name: string
@param master_name: Master node name
@type master_uuid: string
@param master_uuid: Master node UUID
"""
if node.name == master_name:
if node.uuid == master_uuid:
return constants.NR_MASTER
elif node.master_candidate:
return constants.NR_MCANDIDATE
......
......@@ -886,6 +886,27 @@ class R_2_groups_name_assign_nodes(baserlib.OpcodeResource):
})
def _ConvertUsbDevices(data):
"""Convert in place the usb_devices string to the proper format.
In Ganeti 2.8.4 the separator for the usb_devices hvparam was changed from
comma to space because commas cannot be accepted on the command line
(they already act as the separator between different hvparams). RAPI
should be able to accept commas for backwards compatibility, but we want
it to also accept the new space separator. Therefore, we convert
spaces into commas here and keep the old parsing logic elsewhere.
"""
try:
hvparams = data["hvparams"]
usb_devices = hvparams[constants.HV_USB_DEVICES]
hvparams[constants.HV_USB_DEVICES] = usb_devices.replace(" ", ",")
data["hvparams"] = hvparams
except KeyError:
#No usb_devices, no modification required
pass