Commit 73ebb9ff authored by Guido Trotter's avatar Guido Trotter
Browse files

Merge branch 'devel-2.5'



* devel-2.5:
  Allow per-hypervisor optional files
  Add hypervisors ancillary files list
  xen: abstract a few hardcoded strings as constants

Conflicts:
	lib/cmdlib.py
	  - trivial
Signed-off-by: default avatarGuido Trotter <ultrotter@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parents 487895ed 0ad1ea40
......@@ -205,7 +205,7 @@ def _BuildUploadFileList():
for hv_name in constants.HYPER_TYPES:
hv_class = hypervisor.GetHypervisorClass(hv_name)
allowed_files.update(hv_class.GetAncillaryFiles())
allowed_files.update(hv_class.GetAncillaryFiles()[0])
return frozenset(allowed_files)
......
......@@ -2080,7 +2080,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
@classmethod
def _VerifyFiles(cls, errorif, nodeinfo, master_node, all_nvinfo,
(files_all, files_all_opt, files_mc, files_vm)):
(files_all, files_opt, files_mc, files_vm)):
"""Verifies file checksums collected from all nodes.
@param errorif: Callback for reporting errors
......@@ -2089,14 +2089,9 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
@param all_nvinfo: RPC results
"""
assert (len(files_all | files_all_opt | files_mc | files_vm) ==
sum(map(len, [files_all, files_all_opt, files_mc, files_vm]))), \
"Found file listed in more than one file list"
# Define functions determining which nodes to consider for a file
files2nodefn = [
(files_all, None),
(files_all_opt, None),
(files_mc, lambda node: (node.master_candidate or
node.name == master_node)),
(files_vm, lambda node: node.vm_capable),
......@@ -2113,7 +2108,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
frozenset(map(operator.attrgetter("name"), filenodes)))
for filename in files)
assert set(nodefiles) == (files_all | files_all_opt | files_mc | files_vm)
assert set(nodefiles) == (files_all | files_mc | files_vm)
fileinfo = dict((filename, {}) for filename in nodefiles)
ignore_nodes = set()
......@@ -2155,7 +2150,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
# Nodes missing file
missing_file = expected_nodes - with_file
if filename in files_all_opt:
if filename in files_opt:
# All or no nodes
errorif(missing_file and missing_file != expected_nodes,
constants.CV_ECLUSTERFILECHECK, None,
......@@ -3760,6 +3755,7 @@ def _ComputeAncillaryFiles(cluster, redist):
constants.CLUSTER_DOMAIN_SECRET_FILE,
constants.SPICE_CERT_FILE,
constants.SPICE_CACERT_FILE,
constants.RAPI_USERS_FILE,
])
if not redist:
......@@ -3772,8 +3768,10 @@ def _ComputeAncillaryFiles(cluster, redist):
if cluster.modify_etc_hosts:
files_all.add(constants.ETC_HOSTS)
# Files which must either exist on all nodes or on none
files_all_opt = set([
# Files which are optional, these must:
# - be present in one other category as well
# - either exist or not exist on all nodes of that category (mc, vm all)
files_opt = set([
constants.RAPI_USERS_FILE,
])
......@@ -3785,14 +3783,23 @@ def _ComputeAncillaryFiles(cluster, redist):
# Files which should only be on VM-capable nodes
files_vm = set(filename
for hv_name in cluster.enabled_hypervisors
for filename in hypervisor.GetHypervisor(hv_name).GetAncillaryFiles())
for filename in hypervisor.GetHypervisor(hv_name).GetAncillaryFiles()[0])
# Filenames must be unique
assert (len(files_all | files_all_opt | files_mc | files_vm) ==
sum(map(len, [files_all, files_all_opt, files_mc, files_vm]))), \
files_opt |= set(filename
for hv_name in cluster.enabled_hypervisors
for filename in hypervisor.GetHypervisor(hv_name).GetAncillaryFiles()[1])
# Filenames in each category must be unique
all_files_set = files_all | files_mc | files_vm
assert (len(all_files_set) ==
sum(map(len, [files_all, files_mc, files_vm]))), \
"Found file listed in more than one file list"
return (files_all, files_all_opt, files_mc, files_vm)
# Optional files must be present in one other category
assert all_files_set.issuperset(files_opt), \
"Optional file not in a different required list"
return (files_all, files_opt, files_mc, files_vm)
def _RedistributeAncillaryFiles(lu, additional_nodes=None, additional_vm=True):
......@@ -3826,7 +3833,7 @@ def _RedistributeAncillaryFiles(lu, additional_nodes=None, additional_vm=True):
nodelist.remove(master_info.name)
# Gather file lists
(files_all, files_all_opt, files_mc, files_vm) = \
(files_all, _, files_mc, files_vm) = \
_ComputeAncillaryFiles(cluster, True)
# Never re-distribute configuration file from here
......@@ -3836,7 +3843,6 @@ def _RedistributeAncillaryFiles(lu, additional_nodes=None, additional_vm=True):
filemap = [
(online_nodes, files_all),
(online_nodes, files_all_opt),
(vm_nodes, files_vm),
]
......
......@@ -161,6 +161,7 @@ class BaseHypervisor(object):
"""
PARAMETERS = {}
ANCILLARY_FILES = []
ANCILLARY_FILES_OPT = []
CAN_MIGRATE = False
def __init__(self):
......@@ -249,13 +250,16 @@ class BaseHypervisor(object):
"""Return a list of ancillary files to be copied to all nodes as ancillary
configuration files.
@rtype: list of strings
@return: list of absolute paths of files to ship cluster-wide
@rtype: (list of absolute paths, list of absolute paths)
@return: (all files, optional files)
"""
# By default we return a member variable, so that if an hypervisor has just
# a static list of files it doesn't have to override this function.
return cls.ANCILLARY_FILES
assert set(cls.ANCILLARY_FILES).issuperset(cls.ANCILLARY_FILES_OPT), \
"Optional ancillary files must be a subset of ancillary files"
return (cls.ANCILLARY_FILES, cls.ANCILLARY_FILES_OPT)
def Verify(self):
"""Verify the hypervisor.
......
......@@ -493,6 +493,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
ANCILLARY_FILES = [
_KVM_NETWORK_SCRIPT,
]
ANCILLARY_FILES_OPT = [
_KVM_NETWORK_SCRIPT,
]
def __init__(self):
hv_base.BaseHypervisor.__init__(self)
......
......@@ -34,6 +34,11 @@ from ganeti import netutils
from ganeti import objects
XEND_CONFIG_FILE = "/etc/xen/xend-config.sxp"
XL_CONFIG_FILE = "/etc/xen/xl.conf"
VIF_BRIDGE_SCRIPT = "/etc/xen/scripts/vif-bridge"
class XenHypervisor(hv_base.BaseHypervisor):
"""Xen generic hypervisor interface
......@@ -46,9 +51,12 @@ class XenHypervisor(hv_base.BaseHypervisor):
REBOOT_RETRY_INTERVAL = 10
ANCILLARY_FILES = [
"/etc/xen/xend-config.sxp",
"/etc/xen/xl.conf",
"/etc/xen/scripts/vif-bridge",
XEND_CONFIG_FILE,
XL_CONFIG_FILE,
VIF_BRIDGE_SCRIPT,
]
ANCILLARY_FILES_OPT = [
XL_CONFIG_FILE,
]
@staticmethod
......@@ -652,6 +660,9 @@ class XenHvmHypervisor(XenHypervisor):
ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
constants.VNC_PASSWORD_FILE,
]
ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
constants.VNC_PASSWORD_FILE,
]
PARAMETERS = {
constants.HV_ACPI: hv_base.NO_CHECK,
......
......@@ -40,6 +40,7 @@ from ganeti import ht
from ganeti import objects
from ganeti import compat
from ganeti import rpc
from ganeti.hypervisor import hv_xen
import testutils
import mocks
......@@ -289,11 +290,12 @@ class TestClusterVerifyFiles(unittest.TestCase):
errors = []
master_name = "master.example.com"
nodeinfo = [
objects.Node(name=master_name, offline=False),
objects.Node(name="node2.example.com", offline=False),
objects.Node(name="node3.example.com", master_candidate=True),
objects.Node(name="node4.example.com", offline=False),
objects.Node(name="nodata.example.com"),
objects.Node(name=master_name, offline=False, vm_capable=True),
objects.Node(name="node2.example.com", offline=False, vm_capable=True),
objects.Node(name="node3.example.com", master_candidate=True,
vm_capable=False),
objects.Node(name="node4.example.com", offline=False, vm_capable=True),
objects.Node(name="nodata.example.com", offline=False, vm_capable=True),
objects.Node(name="offline.example.com", offline=True),
]
cluster = objects.Cluster(modify_etc_hosts=True,
......@@ -301,24 +303,34 @@ class TestClusterVerifyFiles(unittest.TestCase):
files_all = set([
constants.CLUSTER_DOMAIN_SECRET_FILE,
constants.RAPI_CERT_FILE,
constants.RAPI_USERS_FILE,
])
files_all_opt = set([
files_opt = set([
constants.RAPI_USERS_FILE,
hv_xen.XL_CONFIG_FILE,
constants.VNC_PASSWORD_FILE,
])
files_mc = set([
constants.CLUSTER_CONF_FILE,
])
files_vm = set()
files_vm = set([
hv_xen.XEND_CONFIG_FILE,
hv_xen.XL_CONFIG_FILE,
constants.VNC_PASSWORD_FILE,
])
nvinfo = {
master_name: rpc.RpcResult(data=(True, {
constants.NV_FILELIST: {
constants.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
constants.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
constants.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
}})),
"node2.example.com": rpc.RpcResult(data=(True, {
constants.NV_FILELIST: {
constants.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
}
})),
"node3.example.com": rpc.RpcResult(data=(True, {
......@@ -333,6 +345,7 @@ class TestClusterVerifyFiles(unittest.TestCase):
constants.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
constants.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
constants.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
}
})),
"nodata.example.com": rpc.RpcResult(data=(True, {})),
......@@ -342,7 +355,7 @@ class TestClusterVerifyFiles(unittest.TestCase):
self._VerifyFiles(compat.partial(self._FakeErrorIf, errors), nodeinfo,
master_name, nvinfo,
(files_all, files_all_opt, files_mc, files_vm))
(files_all, files_opt, files_mc, files_vm))
self.assertEqual(sorted(errors), sorted([
(None, ("File %s found with 2 different checksums (variant 1 on"
" node2.example.com, node3.example.com, node4.example.com;"
......@@ -351,6 +364,8 @@ class TestClusterVerifyFiles(unittest.TestCase):
constants.CLUSTER_DOMAIN_SECRET_FILE)),
(None, ("File %s should not exist on node(s) node4.example.com" %
constants.CLUSTER_CONF_FILE)),
(None, ("File %s is missing from node(s) node4.example.com" %
hv_xen.XEND_CONFIG_FILE)),
(None, ("File %s is missing from node(s) node3.example.com" %
constants.CLUSTER_CONF_FILE)),
(None, ("File %s found with 2 different checksums (variant 1 on"
......@@ -359,6 +374,8 @@ class TestClusterVerifyFiles(unittest.TestCase):
(None, ("File %s is optional, but it must exist on all or no nodes (not"
" found on master.example.com, node2.example.com,"
" node3.example.com)" % constants.RAPI_USERS_FILE)),
(None, ("File %s is optional, but it must exist on all or no nodes (not"
" found on node2.example.com)" % hv_xen.XL_CONFIG_FILE)),
("nodata.example.com", "Node did not return file checksum data"),
]))
......
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