4 # Copyright (C) 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """File storage functions.
29 from ganeti import compat
30 from ganeti import constants
31 from ganeti import errors
32 from ganeti import pathutils
33 from ganeti import utils
36 def GetFileStorageSpaceInfo(path):
37 """Retrieves the free and total space of the device where the file is
41 @param path: Path of the file whose embracing device's capacity is
43 @return: a dictionary containing 'vg_size' and 'vg_free' given in MebiBytes
47 result = os.statvfs(path)
48 free = (result.f_frsize * result.f_bavail) / (1024 * 1024)
49 size = (result.f_frsize * result.f_blocks) / (1024 * 1024)
50 return {"type": constants.ST_FILE,
55 raise errors.CommandError("Failed to retrieve file system information about"
56 " path: %s - %s" % (path, e.strerror))
59 def _GetForbiddenFileStoragePaths():
60 """Builds a list of path prefixes which shouldn't be used for file storage.
75 for prefix in ["", "/usr", "/usr/local"]:
76 paths.update(map(lambda s: "%s/%s" % (prefix, s),
77 ["bin", "lib", "lib32", "lib64", "sbin"]))
79 return compat.UniqueFrozenset(map(os.path.normpath, paths))
82 def _ComputeWrongFileStoragePaths(paths,
83 _forbidden=_GetForbiddenFileStoragePaths()):
84 """Cross-checks a list of paths for prefixes considered bad.
86 Some paths, e.g. "/bin", should not be used for file storage.
89 @param paths: List of paths to be checked
91 @return: Sorted list of paths for which the user should be warned
95 return (not os.path.isabs(path) or
97 filter(lambda p: utils.IsBelowDir(p, path), _forbidden))
99 return utils.NiceSort(filter(_Check, map(os.path.normpath, paths)))
102 def ComputeWrongFileStoragePaths(_filename=pathutils.FILE_STORAGE_PATHS_FILE):
103 """Returns a list of file storage paths whose prefix is considered bad.
105 See L{_ComputeWrongFileStoragePaths}.
108 return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename))
111 def _CheckFileStoragePath(path, allowed, exact_match_ok=False):
112 """Checks if a path is in a list of allowed paths for file storage.
115 @param path: Path to check
117 @param allowed: List of allowed paths
118 @type exact_match_ok: bool
119 @param exact_match_ok: whether or not it is okay when the path is exactly
120 equal to an allowed path and not a subdir of it
121 @raise errors.FileStoragePathError: If the path is not allowed
124 if not os.path.isabs(path):
125 raise errors.FileStoragePathError("File storage path must be absolute,"
129 if not os.path.isabs(i):
130 logging.info("Ignoring relative path '%s' for file storage", i)
134 if os.path.normpath(i) == os.path.normpath(path):
137 if utils.IsBelowDir(i, path):
140 raise errors.FileStoragePathError("Path '%s' is not acceptable for file"
144 def _LoadAllowedFileStoragePaths(filename):
145 """Loads file containing allowed file storage paths.
148 @return: List of allowed paths (can be an empty list)
152 contents = utils.ReadFile(filename)
153 except EnvironmentError:
156 return utils.FilterEmptyLinesAndComments(contents)
159 def CheckFileStoragePathAcceptance(
160 path, _filename=pathutils.FILE_STORAGE_PATHS_FILE,
161 exact_match_ok=False):
162 """Checks if a path is allowed for file storage.
165 @param path: Path to check
166 @raise errors.FileStoragePathError: If the path is not allowed
169 allowed = _LoadAllowedFileStoragePaths(_filename)
171 raise errors.FileStoragePathError("No paths are valid or path file '%s'"
172 " was not accessible." % _filename)
174 if _ComputeWrongFileStoragePaths([path]):
175 raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" %
178 _CheckFileStoragePath(path, allowed, exact_match_ok=exact_match_ok)
181 def _CheckFileStoragePathExistance(path):
182 """Checks whether the given path is usable on the file system.
184 This checks wether the path is existing, a directory and writable.
187 @param path: path to check
190 if not os.path.isdir(path):
191 raise errors.FileStoragePathError("Path '%s' is not existing or not a"
192 " directory." % path)
193 if not os.access(path, os.W_OK):
194 raise errors.FileStoragePathError("Path '%s' is not writable" % path)
197 def CheckFileStoragePath(
198 path, _allowed_paths_file=pathutils.FILE_STORAGE_PATHS_FILE):
199 """Checks whether the path exists and is acceptable to use.
202 @param path: path to check
204 @returns: error message if the path is not ready to use
208 CheckFileStoragePathAcceptance(path, _filename=_allowed_paths_file,
210 except errors.FileStoragePathError as e:
212 if not os.path.isdir(path):
213 return "Path '%s' is not exisiting or not a directory." % path
214 if not os.access(path, os.W_OK):
215 return "Path '%s' is not writable" % path