Commit 13a6c760 authored by Helga Velroyen's avatar Helga Velroyen

Prepare verification code for new file path verification

This patch prepares the verification code for adding
a new verification step for the file storage paths:
- It moves a couple of file storage helper functions from
  bdev to filestorage (since they make more sense there
  and bdev is too big anyway).
- They rename constants and functions related to the
  verification step where the allowed file paths are
  checked agains forbidden paths to a more expressive name,
  because otherwise they would be confused to be related
  to the verification of the file storage paths against
  the allowed file storage paths.
- Use the cluster objects helper functions to check
  if file storage is inabled instead of using the utils
  function directly, because it simplifies the code.
Signed-off-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parent 2dcb5a26
......@@ -1130,9 +1130,9 @@ def VerifyNode(what, cluster_name, all_hvparams):
for bridge in what[constants.NV_BRIDGES]
if not utils.BridgeExists(bridge)]
if what.get(constants.NV_FILE_STORAGE_PATHS) == my_name:
result[constants.NV_FILE_STORAGE_PATHS] = \
bdev.ComputeWrongFileStoragePaths()
if what.get(constants.NV_ACCEPTED_STORAGE_PATHS) == my_name:
result[constants.NV_ACCEPTED_STORAGE_PATHS] = \
filestorage.ComputeWrongFileStoragePaths()
return result
......@@ -3195,7 +3195,7 @@ def _TransformFileStorageDir(fs_dir):
@return: the normalized path if valid, None otherwise
"""
bdev.CheckFileStoragePath(fs_dir)
filestorage.CheckFileStoragePath(fs_dir)
return os.path.normpath(fs_dir)
......
......@@ -2294,8 +2294,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
" but missing on this node: %s",
self.cfg.GetNodeName(base.uuid), utils.CommaJoin(missing))
def _VerifyFileStoragePaths(self, ninfo, nresult, is_master,
enabled_disk_templates):
def _VerifyAcceptedFileStoragePaths(self, ninfo, nresult, is_master):
"""Verifies paths in L{pathutils.FILE_STORAGE_PATHS_FILE}.
@type ninfo: L{objects.Node}
......@@ -2305,11 +2304,12 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
@param is_master: Whether node is the master node
"""
cluster = self.cfg.GetClusterInfo()
if (is_master and
(utils.storage.IsFileStorageEnabled(enabled_disk_templates) or
utils.storage.IsSharedFileStorageEnabled(enabled_disk_templates))):
(cluster.IsFileStorageEnabled() or
cluster.IsSharedFileStorageEnabled())):
try:
fspaths = nresult[constants.NV_FILE_STORAGE_PATHS]
fspaths = nresult[constants.NV_ACCEPTED_STORAGE_PATHS]
except KeyError:
# This should never happen
self._ErrorIf(True, constants.CV_ENODEFILESTORAGEPATHS, ninfo.name,
......@@ -2319,7 +2319,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
"Found forbidden file storage paths: %s",
utils.CommaJoin(fspaths))
else:
self._ErrorIf(constants.NV_FILE_STORAGE_PATHS in nresult,
self._ErrorIf(constants.NV_ACCEPTED_STORAGE_PATHS in nresult,
constants.CV_ENODEFILESTORAGEPATHS, ninfo.name,
"Node should not have returned forbidden file storage"
" paths")
......@@ -2669,8 +2669,11 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
if cluster.IsFileStorageEnabled() or \
cluster.IsSharedFileStorageEnabled():
# Load file storage paths only from master node
node_verify_param[constants.NV_FILE_STORAGE_PATHS] = \
node_verify_param[constants.NV_ACCEPTED_STORAGE_PATHS] = \
self.cfg.GetMasterNodeName()
if cluster.IsFileStorageEnabled():
node_verify_param[constants.NV_FILE_STORAGE_PATH] = \
cluster.file_storage_dir
# bridge checks
# FIXME: this needs to be changed per node-group, not cluster-wide
......@@ -2834,9 +2837,8 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
self._VerifyNodeNetwork(node_i, nresult)
self._VerifyNodeUserScripts(node_i, nresult)
self._VerifyOob(node_i, nresult)
self._VerifyFileStoragePaths(node_i, nresult,
node_i.uuid == master_node_uuid,
cluster.enabled_disk_templates)
self._VerifyAcceptedFileStoragePaths(node_i, nresult,
node_i.uuid == master_node_uuid)
if nimg.vm_capable:
self._UpdateVerifyNodeLVM(node_i, nresult, vg_name, nimg)
......
......@@ -1693,7 +1693,9 @@ NV_DRBDVERSION = "drbd-version"
NV_DRBDLIST = "drbd-list"
NV_EXCLUSIVEPVS = "exclusive-pvs"
NV_FILELIST = "filelist"
NV_FILE_STORAGE_PATHS = "file-storage-paths"
NV_ACCEPTED_STORAGE_PATHS = "allowed-file-storage-paths"
NV_FILE_STORAGE_PATH = "file-storage-path"
NV_SHARED_FILE_STORAGE_PATH = "shared-file-storage-path"
NV_HVINFO = "hvinfo"
NV_HVPARAMS = "hvparms"
NV_HYPERVISOR = "hypervisor"
......
......@@ -35,8 +35,9 @@ from ganeti import objects
from ganeti import compat
from ganeti import pathutils
from ganeti import serializer
from ganeti.storage import drbd
from ganeti.storage import base
from ganeti.storage import drbd
from ganeti.storage import filestorage
class RbdShowmappedJsonError(Exception):
......@@ -57,116 +58,6 @@ def _CheckResult(result):
result.cmd, result.fail_reason, result.output)
def _GetForbiddenFileStoragePaths():
"""Builds a list of path prefixes which shouldn't be used for file storage.
@rtype: frozenset
"""
paths = set([
"/boot",
"/dev",
"/etc",
"/home",
"/proc",
"/root",
"/sys",
])
for prefix in ["", "/usr", "/usr/local"]:
paths.update(map(lambda s: "%s/%s" % (prefix, s),
["bin", "lib", "lib32", "lib64", "sbin"]))
return compat.UniqueFrozenset(map(os.path.normpath, paths))
def _ComputeWrongFileStoragePaths(paths,
_forbidden=_GetForbiddenFileStoragePaths()):
"""Cross-checks a list of paths for prefixes considered bad.
Some paths, e.g. "/bin", should not be used for file storage.
@type paths: list
@param paths: List of paths to be checked
@rtype: list
@return: Sorted list of paths for which the user should be warned
"""
def _Check(path):
return (not os.path.isabs(path) or
path in _forbidden or
filter(lambda p: utils.IsBelowDir(p, path), _forbidden))
return utils.NiceSort(filter(_Check, map(os.path.normpath, paths)))
def ComputeWrongFileStoragePaths(_filename=pathutils.FILE_STORAGE_PATHS_FILE):
"""Returns a list of file storage paths whose prefix is considered bad.
See L{_ComputeWrongFileStoragePaths}.
"""
return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename))
def _CheckFileStoragePath(path, allowed):
"""Checks if a path is in a list of allowed paths for file storage.
@type path: string
@param path: Path to check
@type allowed: list
@param allowed: List of allowed paths
@raise errors.FileStoragePathError: If the path is not allowed
"""
if not os.path.isabs(path):
raise errors.FileStoragePathError("File storage path must be absolute,"
" got '%s'" % path)
for i in allowed:
if not os.path.isabs(i):
logging.info("Ignoring relative path '%s' for file storage", i)
continue
if utils.IsBelowDir(i, path):
break
else:
raise errors.FileStoragePathError("Path '%s' is not acceptable for file"
" storage" % path)
def _LoadAllowedFileStoragePaths(filename):
"""Loads file containing allowed file storage paths.
@rtype: list
@return: List of allowed paths (can be an empty list)
"""
try:
contents = utils.ReadFile(filename)
except EnvironmentError:
return []
else:
return utils.FilterEmptyLinesAndComments(contents)
def CheckFileStoragePath(path, _filename=pathutils.FILE_STORAGE_PATHS_FILE):
"""Checks if a path is allowed for file storage.
@type path: string
@param path: Path to check
@raise errors.FileStoragePathError: If the path is not allowed
"""
allowed = _LoadAllowedFileStoragePaths(_filename)
if _ComputeWrongFileStoragePaths([path]):
raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" %
path)
_CheckFileStoragePath(path, allowed)
class LogicalVolume(base.BlockDev):
"""Logical Volume block device.
......@@ -838,7 +729,7 @@ class FileStorage(base.BlockDev):
self.driver = unique_id[0]
self.dev_path = unique_id[1]
CheckFileStoragePath(self.dev_path)
filestorage.CheckFileStoragePathAcceptance(self.dev_path)
self.Attach()
......@@ -962,7 +853,7 @@ class FileStorage(base.BlockDev):
dev_path = unique_id[1]
CheckFileStoragePath(dev_path)
filestorage.CheckFileStoragePathAcceptance(dev_path)
try:
fd = os.open(dev_path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
......
......@@ -23,10 +23,14 @@
"""
import logging
import os
from ganeti import compat
from ganeti import constants
from ganeti import errors
from ganeti import pathutils
from ganeti import utils
def GetFileStorageSpaceInfo(path):
......@@ -50,3 +54,114 @@ def GetFileStorageSpaceInfo(path):
except OSError, e:
raise errors.CommandError("Failed to retrieve file system information about"
" path: %s - %s" % (path, e.strerror))
def _GetForbiddenFileStoragePaths():
"""Builds a list of path prefixes which shouldn't be used for file storage.
@rtype: frozenset
"""
paths = set([
"/boot",
"/dev",
"/etc",
"/home",
"/proc",
"/root",
"/sys",
])
for prefix in ["", "/usr", "/usr/local"]:
paths.update(map(lambda s: "%s/%s" % (prefix, s),
["bin", "lib", "lib32", "lib64", "sbin"]))
return compat.UniqueFrozenset(map(os.path.normpath, paths))
def _ComputeWrongFileStoragePaths(paths,
_forbidden=_GetForbiddenFileStoragePaths()):
"""Cross-checks a list of paths for prefixes considered bad.
Some paths, e.g. "/bin", should not be used for file storage.
@type paths: list
@param paths: List of paths to be checked
@rtype: list
@return: Sorted list of paths for which the user should be warned
"""
def _Check(path):
return (not os.path.isabs(path) or
path in _forbidden or
filter(lambda p: utils.IsBelowDir(p, path), _forbidden))
return utils.NiceSort(filter(_Check, map(os.path.normpath, paths)))
def ComputeWrongFileStoragePaths(_filename=pathutils.FILE_STORAGE_PATHS_FILE):
"""Returns a list of file storage paths whose prefix is considered bad.
See L{_ComputeWrongFileStoragePaths}.
"""
return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename))
def _CheckFileStoragePath(path, allowed):
"""Checks if a path is in a list of allowed paths for file storage.
@type path: string
@param path: Path to check
@type allowed: list
@param allowed: List of allowed paths
@raise errors.FileStoragePathError: If the path is not allowed
"""
if not os.path.isabs(path):
raise errors.FileStoragePathError("File storage path must be absolute,"
" got '%s'" % path)
for i in allowed:
if not os.path.isabs(i):
logging.info("Ignoring relative path '%s' for file storage", i)
continue
if utils.IsBelowDir(i, path):
break
else:
raise errors.FileStoragePathError("Path '%s' is not acceptable for file"
" storage" % path)
def _LoadAllowedFileStoragePaths(filename):
"""Loads file containing allowed file storage paths.
@rtype: list
@return: List of allowed paths (can be an empty list)
"""
try:
contents = utils.ReadFile(filename)
except EnvironmentError:
return []
else:
return utils.FilterEmptyLinesAndComments(contents)
def CheckFileStoragePathAcceptance(
path, _filename=pathutils.FILE_STORAGE_PATHS_FILE):
"""Checks if a path is allowed for file storage.
@type path: string
@param path: Path to check
@raise errors.FileStoragePathError: If the path is not allowed
"""
allowed = _LoadAllowedFileStoragePaths(_filename)
if _ComputeWrongFileStoragePaths([path]):
raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" %
path)
_CheckFileStoragePath(path, allowed)
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