def _pathTestHelper(self, path, result): if result: self.assert_(utils.IsNormAbsPath(path), msg="Path %s should result absolute and normalized" % path) else: self.assertFalse(utils.IsNormAbsPath(path), msg="Path %s should not result absolute and normalized" % path)
def validate_vnc_parameters(hvparams): vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS] if vnc_bind_address: bound_to_addr = (netutils.IP4Address.IsValid(vnc_bind_address) or netutils.IP6Address.IsValid(vnc_bind_address)) is_interface = netutils.IsValidInterface(vnc_bind_address) is_path = utils.IsNormAbsPath(vnc_bind_address) if not bound_to_addr and not is_interface and not is_path: raise errors.HypervisorError("VNC: The %s parameter must be either" " a valid IP address, an interface name," " or an absolute path" % constants.HV_VNC_BIND_ADDRESS) return True
def Validate(self): """Validates loaded configuration data. """ if not self.get("name"): raise qa_error.Error("Cluster name is required") if not self.get("nodes"): raise qa_error.Error("Need at least one node") if not self.get("instances"): raise qa_error.Error("Need at least one instance") disks = self.GetDiskOptions() if disks is None: raise qa_error.Error("Config option 'disks' must exist") else: for d in disks: if d.get("size") is None or d.get("growth") is None: raise qa_error.Error( "Config options `size` and `growth` must exist" " for all `disks` items") check = self.GetInstanceCheckScript() if check: try: os.stat(check) except EnvironmentError as err: raise qa_error.Error( "Can't find instance check script '%s': %s" % (check, err)) enabled_hv = frozenset(self.GetEnabledHypervisors()) if not enabled_hv: raise qa_error.Error("No hypervisor is enabled") difference = enabled_hv - constants.HYPER_TYPES if difference: raise qa_error.Error("Unknown hypervisor(s) enabled: %s" % utils.CommaJoin(difference)) (vc_master, vc_basedir) = self.GetVclusterSettings() if bool(vc_master) != bool(vc_basedir): raise qa_error.Error( "All or none of the config options '%s' and '%s'" " must be set" % (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY)) if vc_basedir and not utils.IsNormAbsPath(vc_basedir): raise qa_error.Error( "Path given in option '%s' must be absolute and" " normalized" % _VCLUSTER_BASEDIR_KEY)
def testEntryOrder(self): paths = [(path[0], path[1]) for path in ensure_dirs.GetPaths()] # Directories for which permissions have been set seen = set() # Current directory (changes when an entry of type C{DIR} or C{QUEUE_DIR} # is encountered) current_dir = None for (path, pathtype) in paths: self.assertTrue(pathtype in ensure_dirs.ALL_TYPES) self.assertTrue( utils.IsNormAbsPath(path), msg=("Path '%s' is not absolute and/or normalized" % path)) dirname = os.path.dirname(path) if pathtype == ensure_dirs.DIR: self.assertFalse(path in seen, msg=("Directory '%s' was seen before" % path)) current_dir = path seen.add(path) elif pathtype == ensure_dirs.QUEUE_DIR: self.assertTrue( dirname in seen, msg=("Queue directory '%s' was not seen before" % path)) current_dir = path elif pathtype == ensure_dirs.FILE: self.assertFalse(current_dir is None) self.assertTrue( dirname in seen, msg=("Directory '%s' of path '%s' has not been seen" " yet" % (dirname, path))) self.assertTrue( (utils.IsBelowDir(current_dir, path) and current_dir == dirname), msg=("File '%s' not below current directory '%s'" % (path, current_dir))) else: self.fail("Unknown path type '%s'" % (pathtype, ))
utils.ParseMultiCpuMask(cpu_mask) except errors.ParseError: return False return True # Read the BaseHypervisor.PARAMETERS docstring for the syntax of the # _CHECK values # must be a file _FILE_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", os.path.isfile, "not found or not a file") # must be a file or a URL _FILE_OR_URL_CHECK = (lambda x: utils.IsNormAbsPath(x) or utils.IsUrl(x), "must be an absolute normalized path or a URL", lambda x: os.path.isfile(x) or utils.IsUrl(x), "not found or not a file or URL") # must be a directory _DIR_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", os.path.isdir, "not found or not a directory") # CPU mask must be well-formed # TODO: implement node level check for the CPU mask _CPU_MASK_CHECK = (_IsCpuMaskWellFormed, "CPU mask definition is not well-formed", None, None) # Multiple CPU mask must be well-formed _MULTI_CPU_MASK_CHECK = (_IsMultiCpuMaskWellFormed,
class _QaConfig(object): def __init__(self, data): """Initializes instances of this class. """ self._data = data #: Cluster-wide run-time value of the exclusive storage flag self._exclusive_storage = None @staticmethod def LoadPatch(patch_dict, rel_path): """ Loads a single patch. @type patch_dict: dict of string to dict @param patch_dict: A dictionary storing patches by relative path. @type rel_path: string @param rel_path: The relative path to the patch, might or might not exist. """ try: full_path = os.path.join(_QA_BASE_PATH, rel_path) patch = serializer.LoadJson(utils.ReadFile(full_path)) patch_dict[rel_path] = patch except IOError: pass @staticmethod def LoadPatches(): """ Finds and loads all patches supported by the QA. @rtype: dict of string to dict @return: A dictionary of relative path to patch content. """ patches = {} _QaConfig.LoadPatch(patches, _QA_DEFAULT_PATCH) patch_dir_path = os.path.join(_QA_BASE_PATH, _QA_PATCH_DIR) if os.path.exists(patch_dir_path): for filename in os.listdir(patch_dir_path): if filename.endswith(".json"): _QaConfig.LoadPatch(patches, os.path.join(_QA_PATCH_DIR, filename)) return patches @staticmethod def ApplyPatch(data, patch_module, patches, patch_path): """Applies a single patch. @type data: dict (deserialized json) @param data: The QA configuration to modify @type patch_module: module @param patch_module: The json patch module, loaded dynamically @type patches: dict of string to dict @param patches: The dictionary of patch path to content @type patch_path: string @param patch_path: The path to the patch, relative to the QA directory """ patch_content = patches[patch_path] print qa_logging.FormatInfo("Applying patch %s" % patch_path) if not patch_content and patch_path != _QA_DEFAULT_PATCH: print qa_logging.FormatWarning("The patch %s added by the user is empty" % patch_path) patch_module.apply_patch(data, patch_content, in_place=True) @staticmethod def ApplyPatches(data, patch_module, patches): """Applies any patches present, and returns the modified QA configuration. First, patches from the patch directory are applied. They are ordered alphabetically, unless there is an ``order`` file present - any patches listed within are applied in that order, and any remaining ones in alphabetical order again. Finally, the default patch residing in the top-level QA directory is applied. @type data: dict (deserialized json) @param data: The QA configuration to modify @type patch_module: module @param patch_module: The json patch module, loaded dynamically @type patches: dict of string to dict @param patches: The dictionary of patch path to content """ ordered_patches = [] order_path = os.path.join(_QA_BASE_PATH, _QA_PATCH_DIR, _QA_PATCH_ORDER_FILE) if os.path.exists(order_path): order_file = open(order_path, 'r') ordered_patches = order_file.read().splitlines() # Removes empty lines ordered_patches = filter(None, ordered_patches) # Add the patch dir ordered_patches = map(lambda x: os.path.join(_QA_PATCH_DIR, x), ordered_patches) # First the ordered patches for patch in ordered_patches: if patch not in patches: raise qa_error.Error("Patch %s specified in the ordering file does not " "exist" % patch) _QaConfig.ApplyPatch(data, patch_module, patches, patch) # Then the other non-default ones for patch in sorted(patches): if patch != _QA_DEFAULT_PATCH and patch not in ordered_patches: _QaConfig.ApplyPatch(data, patch_module, patches, patch) # Finally the default one if _QA_DEFAULT_PATCH in patches: _QaConfig.ApplyPatch(data, patch_module, patches, _QA_DEFAULT_PATCH) @classmethod def Load(cls, filename): """Loads a configuration file and produces a configuration object. @type filename: string @param filename: Path to configuration file @rtype: L{_QaConfig} """ data = serializer.LoadJson(utils.ReadFile(filename)) # Patch the document using JSON Patch (RFC6902) in file _PATCH_JSON, if # available try: patches = _QaConfig.LoadPatches() # Try to use the module only if there is a non-empty patch present if any(patches.values()): mod = __import__("jsonpatch", fromlist=[]) _QaConfig.ApplyPatches(data, mod, patches) except IOError: pass except ImportError: raise qa_error.Error("For the QA JSON patching feature to work, you " "need to install Python modules 'jsonpatch' and " "'jsonpointer'.") result = cls(dict(map(_ConvertResources, data.items()))) # pylint: disable=E1103 result.Validate() return result def Validate(self): """Validates loaded configuration data. """ if not self.get("name"): raise qa_error.Error("Cluster name is required") if not self.get("nodes"): raise qa_error.Error("Need at least one node") if not self.get("instances"): raise qa_error.Error("Need at least one instance") disks = self.GetDiskOptions() if disks is None: raise qa_error.Error("Config option 'disks' must exist") else: for d in disks: if d.get("size") is None or d.get("growth") is None: raise qa_error.Error("Config options `size` and `growth` must exist" " for all `disks` items") check = self.GetInstanceCheckScript() if check: try: os.stat(check) except EnvironmentError, err: raise qa_error.Error("Can't find instance check script '%s': %s" % (check, err)) enabled_hv = frozenset(self.GetEnabledHypervisors()) if not enabled_hv: raise qa_error.Error("No hypervisor is enabled") difference = enabled_hv - constants.HYPER_TYPES if difference: raise qa_error.Error("Unknown hypervisor(s) enabled: %s" % utils.CommaJoin(difference)) (vc_master, vc_basedir) = self.GetVclusterSettings() if bool(vc_master) != bool(vc_basedir): raise qa_error.Error("All or none of the config options '%s' and '%s'" " must be set" % (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY)) if vc_basedir and not utils.IsNormAbsPath(vc_basedir): raise qa_error.Error("Path given in option '%s' must be absolute and" " normalized" % _VCLUSTER_BASEDIR_KEY)
class _QaConfig(object): def __init__(self, data): """Initializes instances of this class. """ self._data = data #: Cluster-wide run-time value of the exclusive storage flag self._exclusive_storage = None @classmethod def Load(cls, filename): """Loads a configuration file and produces a configuration object. @type filename: string @param filename: Path to configuration file @rtype: L{_QaConfig} """ data = serializer.LoadJson(utils.ReadFile(filename)) # Patch the document using JSON Patch (RFC6902) in file _PATCH_JSON, if # available try: patch = serializer.LoadJson(utils.ReadFile(_PATCH_JSON)) if patch: mod = __import__("jsonpatch", fromlist=[]) data = mod.apply_patch(data, patch) except IOError: pass except ImportError: raise qa_error.Error( "If you want to use the QA JSON patching feature," " you need to install Python modules" " 'jsonpatch' and 'jsonpointer'.") result = cls(dict(map(_ConvertResources, data.items()))) # pylint: disable=E1103 result.Validate() return result def Validate(self): """Validates loaded configuration data. """ if not self.get("name"): raise qa_error.Error("Cluster name is required") if not self.get("nodes"): raise qa_error.Error("Need at least one node") if not self.get("instances"): raise qa_error.Error("Need at least one instance") disks = self.GetDiskOptions() if disks is None: raise qa_error.Error("Config option 'disks' must exist") else: for d in disks: if d.get("size") is None or d.get("growth") is None: raise qa_error.Error( "Config options `size` and `growth` must exist" " for all `disks` items") check = self.GetInstanceCheckScript() if check: try: os.stat(check) except EnvironmentError, err: raise qa_error.Error( "Can't find instance check script '%s': %s" % (check, err)) enabled_hv = frozenset(self.GetEnabledHypervisors()) if not enabled_hv: raise qa_error.Error("No hypervisor is enabled") difference = enabled_hv - constants.HYPER_TYPES if difference: raise qa_error.Error("Unknown hypervisor(s) enabled: %s" % utils.CommaJoin(difference)) (vc_master, vc_basedir) = self.GetVclusterSettings() if bool(vc_master) != bool(vc_basedir): raise qa_error.Error( "All or none of the config options '%s' and '%s'" " must be set" % (_VCLUSTER_MASTER_KEY, _VCLUSTER_BASEDIR_KEY)) if vc_basedir and not utils.IsNormAbsPath(vc_basedir): raise qa_error.Error( "Path given in option '%s' must be absolute and" " normalized" % _VCLUSTER_BASEDIR_KEY)