Revision 13a6c760
b/lib/backend.py | ||
---|---|---|
1130 | 1130 |
for bridge in what[constants.NV_BRIDGES] |
1131 | 1131 |
if not utils.BridgeExists(bridge)] |
1132 | 1132 |
|
1133 |
if what.get(constants.NV_FILE_STORAGE_PATHS) == my_name:
|
|
1134 |
result[constants.NV_FILE_STORAGE_PATHS] = \
|
|
1135 |
bdev.ComputeWrongFileStoragePaths()
|
|
1133 |
if what.get(constants.NV_ACCEPTED_STORAGE_PATHS) == my_name:
|
|
1134 |
result[constants.NV_ACCEPTED_STORAGE_PATHS] = \
|
|
1135 |
filestorage.ComputeWrongFileStoragePaths()
|
|
1136 | 1136 |
|
1137 | 1137 |
return result |
1138 | 1138 |
|
... | ... | |
3195 | 3195 |
@return: the normalized path if valid, None otherwise |
3196 | 3196 |
|
3197 | 3197 |
""" |
3198 |
bdev.CheckFileStoragePath(fs_dir)
|
|
3198 |
filestorage.CheckFileStoragePath(fs_dir)
|
|
3199 | 3199 |
|
3200 | 3200 |
return os.path.normpath(fs_dir) |
3201 | 3201 |
|
b/lib/cmdlib/cluster.py | ||
---|---|---|
2294 | 2294 |
" but missing on this node: %s", |
2295 | 2295 |
self.cfg.GetNodeName(base.uuid), utils.CommaJoin(missing)) |
2296 | 2296 |
|
2297 |
def _VerifyFileStoragePaths(self, ninfo, nresult, is_master, |
|
2298 |
enabled_disk_templates): |
|
2297 |
def _VerifyAcceptedFileStoragePaths(self, ninfo, nresult, is_master): |
|
2299 | 2298 |
"""Verifies paths in L{pathutils.FILE_STORAGE_PATHS_FILE}. |
2300 | 2299 |
|
2301 | 2300 |
@type ninfo: L{objects.Node} |
... | ... | |
2305 | 2304 |
@param is_master: Whether node is the master node |
2306 | 2305 |
|
2307 | 2306 |
""" |
2307 |
cluster = self.cfg.GetClusterInfo() |
|
2308 | 2308 |
if (is_master and |
2309 |
(utils.storage.IsFileStorageEnabled(enabled_disk_templates) or
|
|
2310 |
utils.storage.IsSharedFileStorageEnabled(enabled_disk_templates))):
|
|
2309 |
(cluster.IsFileStorageEnabled() or
|
|
2310 |
cluster.IsSharedFileStorageEnabled())):
|
|
2311 | 2311 |
try: |
2312 |
fspaths = nresult[constants.NV_FILE_STORAGE_PATHS]
|
|
2312 |
fspaths = nresult[constants.NV_ACCEPTED_STORAGE_PATHS]
|
|
2313 | 2313 |
except KeyError: |
2314 | 2314 |
# This should never happen |
2315 | 2315 |
self._ErrorIf(True, constants.CV_ENODEFILESTORAGEPATHS, ninfo.name, |
... | ... | |
2319 | 2319 |
"Found forbidden file storage paths: %s", |
2320 | 2320 |
utils.CommaJoin(fspaths)) |
2321 | 2321 |
else: |
2322 |
self._ErrorIf(constants.NV_FILE_STORAGE_PATHS in nresult,
|
|
2322 |
self._ErrorIf(constants.NV_ACCEPTED_STORAGE_PATHS in nresult,
|
|
2323 | 2323 |
constants.CV_ENODEFILESTORAGEPATHS, ninfo.name, |
2324 | 2324 |
"Node should not have returned forbidden file storage" |
2325 | 2325 |
" paths") |
... | ... | |
2669 | 2669 |
if cluster.IsFileStorageEnabled() or \ |
2670 | 2670 |
cluster.IsSharedFileStorageEnabled(): |
2671 | 2671 |
# Load file storage paths only from master node |
2672 |
node_verify_param[constants.NV_FILE_STORAGE_PATHS] = \
|
|
2672 |
node_verify_param[constants.NV_ACCEPTED_STORAGE_PATHS] = \
|
|
2673 | 2673 |
self.cfg.GetMasterNodeName() |
2674 |
if cluster.IsFileStorageEnabled(): |
|
2675 |
node_verify_param[constants.NV_FILE_STORAGE_PATH] = \ |
|
2676 |
cluster.file_storage_dir |
|
2674 | 2677 |
|
2675 | 2678 |
# bridge checks |
2676 | 2679 |
# FIXME: this needs to be changed per node-group, not cluster-wide |
... | ... | |
2834 | 2837 |
self._VerifyNodeNetwork(node_i, nresult) |
2835 | 2838 |
self._VerifyNodeUserScripts(node_i, nresult) |
2836 | 2839 |
self._VerifyOob(node_i, nresult) |
2837 |
self._VerifyFileStoragePaths(node_i, nresult, |
|
2838 |
node_i.uuid == master_node_uuid, |
|
2839 |
cluster.enabled_disk_templates) |
|
2840 |
self._VerifyAcceptedFileStoragePaths(node_i, nresult, |
|
2841 |
node_i.uuid == master_node_uuid) |
|
2840 | 2842 |
|
2841 | 2843 |
if nimg.vm_capable: |
2842 | 2844 |
self._UpdateVerifyNodeLVM(node_i, nresult, vg_name, nimg) |
b/lib/constants.py | ||
---|---|---|
1693 | 1693 |
NV_DRBDLIST = "drbd-list" |
1694 | 1694 |
NV_EXCLUSIVEPVS = "exclusive-pvs" |
1695 | 1695 |
NV_FILELIST = "filelist" |
1696 |
NV_FILE_STORAGE_PATHS = "file-storage-paths" |
|
1696 |
NV_ACCEPTED_STORAGE_PATHS = "allowed-file-storage-paths" |
|
1697 |
NV_FILE_STORAGE_PATH = "file-storage-path" |
|
1698 |
NV_SHARED_FILE_STORAGE_PATH = "shared-file-storage-path" |
|
1697 | 1699 |
NV_HVINFO = "hvinfo" |
1698 | 1700 |
NV_HVPARAMS = "hvparms" |
1699 | 1701 |
NV_HYPERVISOR = "hypervisor" |
b/lib/storage/bdev.py | ||
---|---|---|
35 | 35 |
from ganeti import compat |
36 | 36 |
from ganeti import pathutils |
37 | 37 |
from ganeti import serializer |
38 |
from ganeti.storage import drbd |
|
39 | 38 |
from ganeti.storage import base |
39 |
from ganeti.storage import drbd |
|
40 |
from ganeti.storage import filestorage |
|
40 | 41 |
|
41 | 42 |
|
42 | 43 |
class RbdShowmappedJsonError(Exception): |
... | ... | |
57 | 58 |
result.cmd, result.fail_reason, result.output) |
58 | 59 |
|
59 | 60 |
|
60 |
def _GetForbiddenFileStoragePaths(): |
|
61 |
"""Builds a list of path prefixes which shouldn't be used for file storage. |
|
62 |
|
|
63 |
@rtype: frozenset |
|
64 |
|
|
65 |
""" |
|
66 |
paths = set([ |
|
67 |
"/boot", |
|
68 |
"/dev", |
|
69 |
"/etc", |
|
70 |
"/home", |
|
71 |
"/proc", |
|
72 |
"/root", |
|
73 |
"/sys", |
|
74 |
]) |
|
75 |
|
|
76 |
for prefix in ["", "/usr", "/usr/local"]: |
|
77 |
paths.update(map(lambda s: "%s/%s" % (prefix, s), |
|
78 |
["bin", "lib", "lib32", "lib64", "sbin"])) |
|
79 |
|
|
80 |
return compat.UniqueFrozenset(map(os.path.normpath, paths)) |
|
81 |
|
|
82 |
|
|
83 |
def _ComputeWrongFileStoragePaths(paths, |
|
84 |
_forbidden=_GetForbiddenFileStoragePaths()): |
|
85 |
"""Cross-checks a list of paths for prefixes considered bad. |
|
86 |
|
|
87 |
Some paths, e.g. "/bin", should not be used for file storage. |
|
88 |
|
|
89 |
@type paths: list |
|
90 |
@param paths: List of paths to be checked |
|
91 |
@rtype: list |
|
92 |
@return: Sorted list of paths for which the user should be warned |
|
93 |
|
|
94 |
""" |
|
95 |
def _Check(path): |
|
96 |
return (not os.path.isabs(path) or |
|
97 |
path in _forbidden or |
|
98 |
filter(lambda p: utils.IsBelowDir(p, path), _forbidden)) |
|
99 |
|
|
100 |
return utils.NiceSort(filter(_Check, map(os.path.normpath, paths))) |
|
101 |
|
|
102 |
|
|
103 |
def ComputeWrongFileStoragePaths(_filename=pathutils.FILE_STORAGE_PATHS_FILE): |
|
104 |
"""Returns a list of file storage paths whose prefix is considered bad. |
|
105 |
|
|
106 |
See L{_ComputeWrongFileStoragePaths}. |
|
107 |
|
|
108 |
""" |
|
109 |
return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename)) |
|
110 |
|
|
111 |
|
|
112 |
def _CheckFileStoragePath(path, allowed): |
|
113 |
"""Checks if a path is in a list of allowed paths for file storage. |
|
114 |
|
|
115 |
@type path: string |
|
116 |
@param path: Path to check |
|
117 |
@type allowed: list |
|
118 |
@param allowed: List of allowed paths |
|
119 |
@raise errors.FileStoragePathError: If the path is not allowed |
|
120 |
|
|
121 |
""" |
|
122 |
if not os.path.isabs(path): |
|
123 |
raise errors.FileStoragePathError("File storage path must be absolute," |
|
124 |
" got '%s'" % path) |
|
125 |
|
|
126 |
for i in allowed: |
|
127 |
if not os.path.isabs(i): |
|
128 |
logging.info("Ignoring relative path '%s' for file storage", i) |
|
129 |
continue |
|
130 |
|
|
131 |
if utils.IsBelowDir(i, path): |
|
132 |
break |
|
133 |
else: |
|
134 |
raise errors.FileStoragePathError("Path '%s' is not acceptable for file" |
|
135 |
" storage" % path) |
|
136 |
|
|
137 |
|
|
138 |
def _LoadAllowedFileStoragePaths(filename): |
|
139 |
"""Loads file containing allowed file storage paths. |
|
140 |
|
|
141 |
@rtype: list |
|
142 |
@return: List of allowed paths (can be an empty list) |
|
143 |
|
|
144 |
""" |
|
145 |
try: |
|
146 |
contents = utils.ReadFile(filename) |
|
147 |
except EnvironmentError: |
|
148 |
return [] |
|
149 |
else: |
|
150 |
return utils.FilterEmptyLinesAndComments(contents) |
|
151 |
|
|
152 |
|
|
153 |
def CheckFileStoragePath(path, _filename=pathutils.FILE_STORAGE_PATHS_FILE): |
|
154 |
"""Checks if a path is allowed for file storage. |
|
155 |
|
|
156 |
@type path: string |
|
157 |
@param path: Path to check |
|
158 |
@raise errors.FileStoragePathError: If the path is not allowed |
|
159 |
|
|
160 |
""" |
|
161 |
allowed = _LoadAllowedFileStoragePaths(_filename) |
|
162 |
|
|
163 |
if _ComputeWrongFileStoragePaths([path]): |
|
164 |
raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" % |
|
165 |
path) |
|
166 |
|
|
167 |
_CheckFileStoragePath(path, allowed) |
|
168 |
|
|
169 |
|
|
170 | 61 |
class LogicalVolume(base.BlockDev): |
171 | 62 |
"""Logical Volume block device. |
172 | 63 |
|
... | ... | |
838 | 729 |
self.driver = unique_id[0] |
839 | 730 |
self.dev_path = unique_id[1] |
840 | 731 |
|
841 |
CheckFileStoragePath(self.dev_path)
|
|
732 |
filestorage.CheckFileStoragePathAcceptance(self.dev_path)
|
|
842 | 733 |
|
843 | 734 |
self.Attach() |
844 | 735 |
|
... | ... | |
962 | 853 |
|
963 | 854 |
dev_path = unique_id[1] |
964 | 855 |
|
965 |
CheckFileStoragePath(dev_path)
|
|
856 |
filestorage.CheckFileStoragePathAcceptance(dev_path)
|
|
966 | 857 |
|
967 | 858 |
try: |
968 | 859 |
fd = os.open(dev_path, os.O_RDWR | os.O_CREAT | os.O_EXCL) |
b/lib/storage/filestorage.py | ||
---|---|---|
23 | 23 |
|
24 | 24 |
""" |
25 | 25 |
|
26 |
import logging |
|
26 | 27 |
import os |
27 | 28 |
|
29 |
from ganeti import compat |
|
28 | 30 |
from ganeti import constants |
29 | 31 |
from ganeti import errors |
32 |
from ganeti import pathutils |
|
33 |
from ganeti import utils |
|
30 | 34 |
|
31 | 35 |
|
32 | 36 |
def GetFileStorageSpaceInfo(path): |
... | ... | |
50 | 54 |
except OSError, e: |
51 | 55 |
raise errors.CommandError("Failed to retrieve file system information about" |
52 | 56 |
" path: %s - %s" % (path, e.strerror)) |
57 |
|
|
58 |
|
|
59 |
def _GetForbiddenFileStoragePaths(): |
|
60 |
"""Builds a list of path prefixes which shouldn't be used for file storage. |
|
61 |
|
|
62 |
@rtype: frozenset |
|
63 |
|
|
64 |
""" |
|
65 |
paths = set([ |
|
66 |
"/boot", |
|
67 |
"/dev", |
|
68 |
"/etc", |
|
69 |
"/home", |
|
70 |
"/proc", |
|
71 |
"/root", |
|
72 |
"/sys", |
|
73 |
]) |
|
74 |
|
|
75 |
for prefix in ["", "/usr", "/usr/local"]: |
|
76 |
paths.update(map(lambda s: "%s/%s" % (prefix, s), |
|
77 |
["bin", "lib", "lib32", "lib64", "sbin"])) |
|
78 |
|
|
79 |
return compat.UniqueFrozenset(map(os.path.normpath, paths)) |
|
80 |
|
|
81 |
|
|
82 |
def _ComputeWrongFileStoragePaths(paths, |
|
83 |
_forbidden=_GetForbiddenFileStoragePaths()): |
|
84 |
"""Cross-checks a list of paths for prefixes considered bad. |
|
85 |
|
|
86 |
Some paths, e.g. "/bin", should not be used for file storage. |
|
87 |
|
|
88 |
@type paths: list |
|
89 |
@param paths: List of paths to be checked |
|
90 |
@rtype: list |
|
91 |
@return: Sorted list of paths for which the user should be warned |
|
92 |
|
|
93 |
""" |
|
94 |
def _Check(path): |
|
95 |
return (not os.path.isabs(path) or |
|
96 |
path in _forbidden or |
|
97 |
filter(lambda p: utils.IsBelowDir(p, path), _forbidden)) |
|
98 |
|
|
99 |
return utils.NiceSort(filter(_Check, map(os.path.normpath, paths))) |
|
100 |
|
|
101 |
|
|
102 |
def ComputeWrongFileStoragePaths(_filename=pathutils.FILE_STORAGE_PATHS_FILE): |
|
103 |
"""Returns a list of file storage paths whose prefix is considered bad. |
|
104 |
|
|
105 |
See L{_ComputeWrongFileStoragePaths}. |
|
106 |
|
|
107 |
""" |
|
108 |
return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename)) |
|
109 |
|
|
110 |
|
|
111 |
def _CheckFileStoragePath(path, allowed): |
|
112 |
"""Checks if a path is in a list of allowed paths for file storage. |
|
113 |
|
|
114 |
@type path: string |
|
115 |
@param path: Path to check |
|
116 |
@type allowed: list |
|
117 |
@param allowed: List of allowed paths |
|
118 |
@raise errors.FileStoragePathError: If the path is not allowed |
|
119 |
|
|
120 |
""" |
|
121 |
if not os.path.isabs(path): |
|
122 |
raise errors.FileStoragePathError("File storage path must be absolute," |
|
123 |
" got '%s'" % path) |
|
124 |
|
|
125 |
for i in allowed: |
|
126 |
if not os.path.isabs(i): |
|
127 |
logging.info("Ignoring relative path '%s' for file storage", i) |
|
128 |
continue |
|
129 |
|
|
130 |
if utils.IsBelowDir(i, path): |
|
131 |
break |
|
132 |
else: |
|
133 |
raise errors.FileStoragePathError("Path '%s' is not acceptable for file" |
|
134 |
" storage" % path) |
|
135 |
|
|
136 |
|
|
137 |
def _LoadAllowedFileStoragePaths(filename): |
|
138 |
"""Loads file containing allowed file storage paths. |
|
139 |
|
|
140 |
@rtype: list |
|
141 |
@return: List of allowed paths (can be an empty list) |
|
142 |
|
|
143 |
""" |
|
144 |
try: |
|
145 |
contents = utils.ReadFile(filename) |
|
146 |
except EnvironmentError: |
|
147 |
return [] |
|
148 |
else: |
|
149 |
return utils.FilterEmptyLinesAndComments(contents) |
|
150 |
|
|
151 |
|
|
152 |
def CheckFileStoragePathAcceptance( |
|
153 |
path, _filename=pathutils.FILE_STORAGE_PATHS_FILE): |
|
154 |
"""Checks if a path is allowed for file storage. |
|
155 |
|
|
156 |
@type path: string |
|
157 |
@param path: Path to check |
|
158 |
@raise errors.FileStoragePathError: If the path is not allowed |
|
159 |
|
|
160 |
""" |
|
161 |
allowed = _LoadAllowedFileStoragePaths(_filename) |
|
162 |
|
|
163 |
if _ComputeWrongFileStoragePaths([path]): |
|
164 |
raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" % |
|
165 |
path) |
|
166 |
|
|
167 |
_CheckFileStoragePath(path, allowed) |
Also available in: Unified diff