diff --git a/lib/backend.py b/lib/backend.py
index 4b1af8b5cd78b5342201776b66cadbda5f817646..820538108abf3c8d1af9ba14ff9f975ba7aa9f2b 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -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)
 
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 8ec6f4a859bf04f895095f4c173af054fa70f713..23ee2e922d946054747d1fc93eade987fd10dbe5 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -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),
     ]
 
diff --git a/lib/hypervisor/hv_base.py b/lib/hypervisor/hv_base.py
index 824842c66b75a826665392e867d911fe368f0ebd..44f80e1558516561d8743b7c2389f57453e9f87f 100644
--- a/lib/hypervisor/hv_base.py
+++ b/lib/hypervisor/hv_base.py
@@ -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.
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 577608afdde1e8aca72c7c798c2a3e89c33173f7..07017ca32f88e0084fd4ba2d3d99737ac3e1ce77 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -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)
diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py
index 7e2418f203dfa09e5cb7a0e5703a3c79954b5d66..8fbc2b96c6bf730909d6a9000aa04d7978da54a2 100644
--- a/lib/hypervisor/hv_xen.py
+++ b/lib/hypervisor/hv_xen.py
@@ -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,
diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py
index 6846004985d0067148fdc095ba8d009bd2788c3f..778d8604a0001b7056caecf20cd2427cd4d3597d 100755
--- a/test/ganeti.cmdlib_unittest.py
+++ b/test/ganeti.cmdlib_unittest.py
@@ -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"),
       ]))