Revision 9c1c3c19
b/lib/backend.py | ||
---|---|---|
1134 | 1134 |
result[constants.NV_ACCEPTED_STORAGE_PATHS] = \ |
1135 | 1135 |
filestorage.ComputeWrongFileStoragePaths() |
1136 | 1136 |
|
1137 |
if what.get(constants.NV_FILE_STORAGE_PATH): |
|
1138 |
pathresult = filestorage.CheckFileStoragePath( |
|
1139 |
what[constants.NV_FILE_STORAGE_PATH]) |
|
1140 |
if pathresult: |
|
1141 |
result[constants.NV_FILE_STORAGE_PATH] = pathresult |
|
1142 |
|
|
1137 | 1143 |
return result |
1138 | 1144 |
|
1139 | 1145 |
|
b/lib/cmdlib/cluster.py | ||
---|---|---|
2324 | 2324 |
"Node should not have returned forbidden file storage" |
2325 | 2325 |
" paths") |
2326 | 2326 |
|
2327 |
def _VerifyStoragePaths(self, ninfo, nresult): |
|
2328 |
"""Verifies (file) storage paths. |
|
2329 |
|
|
2330 |
@type ninfo: L{objects.Node} |
|
2331 |
@param ninfo: the node to check |
|
2332 |
@param nresult: the remote results for the node |
|
2333 |
|
|
2334 |
""" |
|
2335 |
cluster = self.cfg.GetClusterInfo() |
|
2336 |
if cluster.IsFileStorageEnabled(): |
|
2337 |
self._ErrorIf( |
|
2338 |
constants.NV_FILE_STORAGE_PATH in nresult, |
|
2339 |
constants.CV_ENODEFILESTORAGEPATHUNUSABLE, ninfo.name, |
|
2340 |
"The configured file storage path is unusable: %s" % |
|
2341 |
nresult.get(constants.NV_FILE_STORAGE_PATH)) |
|
2342 |
|
|
2327 | 2343 |
def _VerifyOob(self, ninfo, nresult): |
2328 | 2344 |
"""Verifies out of band functionality of a node. |
2329 | 2345 |
|
... | ... | |
2839 | 2855 |
self._VerifyOob(node_i, nresult) |
2840 | 2856 |
self._VerifyAcceptedFileStoragePaths(node_i, nresult, |
2841 | 2857 |
node_i.uuid == master_node_uuid) |
2858 |
self._VerifyStoragePaths(node_i, nresult) |
|
2842 | 2859 |
|
2843 | 2860 |
if nimg.vm_capable: |
2844 | 2861 |
self._UpdateVerifyNodeLVM(node_i, nresult, vg_name, nimg) |
b/lib/constants.py | ||
---|---|---|
1647 | 1647 |
(CV_TNODE, "ENODEUSERSCRIPTS", "User scripts not present or not executable") |
1648 | 1648 |
CV_ENODEFILESTORAGEPATHS = \ |
1649 | 1649 |
(CV_TNODE, "ENODEFILESTORAGEPATHS", "Detected bad file storage paths") |
1650 |
CV_ENODEFILESTORAGEPATHUNUSABLE = \ |
|
1651 |
(CV_TNODE, "ENODEFILESTORAGEPATHUNUSABLE", "File storage path unusable") |
|
1650 | 1652 |
|
1651 | 1653 |
CV_ALL_ECODES = compat.UniqueFrozenset([ |
1652 | 1654 |
CV_ECLUSTERCFG, |
... | ... | |
1681 | 1683 |
CV_ENODEOOBPATH, |
1682 | 1684 |
CV_ENODEUSERSCRIPTS, |
1683 | 1685 |
CV_ENODEFILESTORAGEPATHS, |
1686 |
CV_ENODEFILESTORAGEPATHUNUSABLE, |
|
1684 | 1687 |
]) |
1685 | 1688 |
|
1686 | 1689 |
CV_ALL_ECODES_STRINGS = \ |
b/lib/storage/filestorage.py | ||
---|---|---|
108 | 108 |
return _ComputeWrongFileStoragePaths(_LoadAllowedFileStoragePaths(_filename)) |
109 | 109 |
|
110 | 110 |
|
111 |
def _CheckFileStoragePath(path, allowed): |
|
111 |
def _CheckFileStoragePath(path, allowed, exact_match_ok=False):
|
|
112 | 112 |
"""Checks if a path is in a list of allowed paths for file storage. |
113 | 113 |
|
114 | 114 |
@type path: string |
115 | 115 |
@param path: Path to check |
116 | 116 |
@type allowed: list |
117 | 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 |
|
118 | 121 |
@raise errors.FileStoragePathError: If the path is not allowed |
119 | 122 |
|
120 | 123 |
""" |
... | ... | |
127 | 130 |
logging.info("Ignoring relative path '%s' for file storage", i) |
128 | 131 |
continue |
129 | 132 |
|
133 |
if exact_match_ok: |
|
134 |
if os.path.normpath(i) == os.path.normpath(path): |
|
135 |
break |
|
136 |
|
|
130 | 137 |
if utils.IsBelowDir(i, path): |
131 | 138 |
break |
132 | 139 |
else: |
... | ... | |
150 | 157 |
|
151 | 158 |
|
152 | 159 |
def CheckFileStoragePathAcceptance( |
153 |
path, _filename=pathutils.FILE_STORAGE_PATHS_FILE): |
|
160 |
path, _filename=pathutils.FILE_STORAGE_PATHS_FILE, |
|
161 |
exact_match_ok=False): |
|
154 | 162 |
"""Checks if a path is allowed for file storage. |
155 | 163 |
|
156 | 164 |
@type path: string |
... | ... | |
164 | 172 |
raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" % |
165 | 173 |
path) |
166 | 174 |
|
167 |
_CheckFileStoragePath(path, allowed) |
|
175 |
_CheckFileStoragePath(path, allowed, exact_match_ok=exact_match_ok) |
|
176 |
|
|
177 |
|
|
178 |
def _CheckFileStoragePathExistance(path): |
|
179 |
"""Checks whether the given path is usable on the file system. |
|
180 |
|
|
181 |
This checks wether the path is existing, a directory and writable. |
|
182 |
|
|
183 |
@type path: string |
|
184 |
@param path: path to check |
|
185 |
|
|
186 |
""" |
|
187 |
if not os.path.isdir(path): |
|
188 |
raise errors.FileStoragePathError("Path '%s' is not exisiting or not a" |
|
189 |
" directory." % path) |
|
190 |
if not os.access(path, os.W_OK): |
|
191 |
raise errors.FileStoragePathError("Path '%s' is not writable" % path) |
|
192 |
|
|
193 |
|
|
194 |
def CheckFileStoragePath( |
|
195 |
path, _allowed_paths_file=pathutils.FILE_STORAGE_PATHS_FILE): |
|
196 |
"""Checks whether the path exists and is acceptable to use. |
|
197 |
|
|
198 |
@type path: string |
|
199 |
@param path: path to check |
|
200 |
@rtype: string |
|
201 |
@returns: error message if the path is not ready to use |
|
202 |
|
|
203 |
""" |
|
204 |
try: |
|
205 |
CheckFileStoragePathAcceptance(path, _filename=_allowed_paths_file, |
|
206 |
exact_match_ok=True) |
|
207 |
except errors.FileStoragePathError, e: |
|
208 |
return e.message |
|
209 |
if not os.path.isdir(path): |
|
210 |
return "Path '%s' is not exisiting or not a directory." % path |
|
211 |
if not os.access(path, os.W_OK): |
|
212 |
return "Path '%s' is not writable" % path |
b/src/Ganeti/Types.hs | ||
---|---|---|
234 | 234 |
|
235 | 235 |
-- | Cluster verify error codes. |
236 | 236 |
$(THH.declareSADT "CVErrorCode" |
237 |
[ ("CvECLUSTERCFG", 'C.cvEclustercfgCode) |
|
238 |
, ("CvECLUSTERCERT", 'C.cvEclustercertCode) |
|
239 |
, ("CvECLUSTERFILECHECK", 'C.cvEclusterfilecheckCode) |
|
240 |
, ("CvECLUSTERDANGLINGNODES", 'C.cvEclusterdanglingnodesCode) |
|
241 |
, ("CvECLUSTERDANGLINGINST", 'C.cvEclusterdanglinginstCode) |
|
242 |
, ("CvEINSTANCEBADNODE", 'C.cvEinstancebadnodeCode) |
|
243 |
, ("CvEINSTANCEDOWN", 'C.cvEinstancedownCode) |
|
244 |
, ("CvEINSTANCELAYOUT", 'C.cvEinstancelayoutCode) |
|
245 |
, ("CvEINSTANCEMISSINGDISK", 'C.cvEinstancemissingdiskCode) |
|
246 |
, ("CvEINSTANCEFAULTYDISK", 'C.cvEinstancefaultydiskCode) |
|
247 |
, ("CvEINSTANCEWRONGNODE", 'C.cvEinstancewrongnodeCode) |
|
248 |
, ("CvEINSTANCESPLITGROUPS", 'C.cvEinstancesplitgroupsCode) |
|
249 |
, ("CvEINSTANCEPOLICY", 'C.cvEinstancepolicyCode) |
|
250 |
, ("CvENODEDRBD", 'C.cvEnodedrbdCode) |
|
251 |
, ("CvENODEDRBDHELPER", 'C.cvEnodedrbdhelperCode) |
|
252 |
, ("CvENODEFILECHECK", 'C.cvEnodefilecheckCode) |
|
253 |
, ("CvENODEHOOKS", 'C.cvEnodehooksCode) |
|
254 |
, ("CvENODEHV", 'C.cvEnodehvCode) |
|
255 |
, ("CvENODELVM", 'C.cvEnodelvmCode) |
|
256 |
, ("CvENODEN1", 'C.cvEnoden1Code) |
|
257 |
, ("CvENODENET", 'C.cvEnodenetCode) |
|
258 |
, ("CvENODEOS", 'C.cvEnodeosCode) |
|
259 |
, ("CvENODEORPHANINSTANCE", 'C.cvEnodeorphaninstanceCode) |
|
260 |
, ("CvENODEORPHANLV", 'C.cvEnodeorphanlvCode) |
|
261 |
, ("CvENODERPC", 'C.cvEnoderpcCode) |
|
262 |
, ("CvENODESSH", 'C.cvEnodesshCode) |
|
263 |
, ("CvENODEVERSION", 'C.cvEnodeversionCode) |
|
264 |
, ("CvENODESETUP", 'C.cvEnodesetupCode) |
|
265 |
, ("CvENODETIME", 'C.cvEnodetimeCode) |
|
266 |
, ("CvENODEOOBPATH", 'C.cvEnodeoobpathCode) |
|
267 |
, ("CvENODEUSERSCRIPTS", 'C.cvEnodeuserscriptsCode) |
|
268 |
, ("CvENODEFILESTORAGEPATHS", 'C.cvEnodefilestoragepathsCode) |
|
237 |
[ ("CvECLUSTERCFG", 'C.cvEclustercfgCode) |
|
238 |
, ("CvECLUSTERCERT", 'C.cvEclustercertCode) |
|
239 |
, ("CvECLUSTERFILECHECK", 'C.cvEclusterfilecheckCode) |
|
240 |
, ("CvECLUSTERDANGLINGNODES", 'C.cvEclusterdanglingnodesCode) |
|
241 |
, ("CvECLUSTERDANGLINGINST", 'C.cvEclusterdanglinginstCode) |
|
242 |
, ("CvEINSTANCEBADNODE", 'C.cvEinstancebadnodeCode) |
|
243 |
, ("CvEINSTANCEDOWN", 'C.cvEinstancedownCode) |
|
244 |
, ("CvEINSTANCELAYOUT", 'C.cvEinstancelayoutCode) |
|
245 |
, ("CvEINSTANCEMISSINGDISK", 'C.cvEinstancemissingdiskCode) |
|
246 |
, ("CvEINSTANCEFAULTYDISK", 'C.cvEinstancefaultydiskCode) |
|
247 |
, ("CvEINSTANCEWRONGNODE", 'C.cvEinstancewrongnodeCode) |
|
248 |
, ("CvEINSTANCESPLITGROUPS", 'C.cvEinstancesplitgroupsCode) |
|
249 |
, ("CvEINSTANCEPOLICY", 'C.cvEinstancepolicyCode) |
|
250 |
, ("CvENODEDRBD", 'C.cvEnodedrbdCode) |
|
251 |
, ("CvENODEDRBDHELPER", 'C.cvEnodedrbdhelperCode) |
|
252 |
, ("CvENODEFILECHECK", 'C.cvEnodefilecheckCode) |
|
253 |
, ("CvENODEHOOKS", 'C.cvEnodehooksCode) |
|
254 |
, ("CvENODEHV", 'C.cvEnodehvCode) |
|
255 |
, ("CvENODELVM", 'C.cvEnodelvmCode) |
|
256 |
, ("CvENODEN1", 'C.cvEnoden1Code) |
|
257 |
, ("CvENODENET", 'C.cvEnodenetCode) |
|
258 |
, ("CvENODEOS", 'C.cvEnodeosCode) |
|
259 |
, ("CvENODEORPHANINSTANCE", 'C.cvEnodeorphaninstanceCode) |
|
260 |
, ("CvENODEORPHANLV", 'C.cvEnodeorphanlvCode) |
|
261 |
, ("CvENODERPC", 'C.cvEnoderpcCode) |
|
262 |
, ("CvENODESSH", 'C.cvEnodesshCode) |
|
263 |
, ("CvENODEVERSION", 'C.cvEnodeversionCode) |
|
264 |
, ("CvENODESETUP", 'C.cvEnodesetupCode) |
|
265 |
, ("CvENODETIME", 'C.cvEnodetimeCode) |
|
266 |
, ("CvENODEOOBPATH", 'C.cvEnodeoobpathCode) |
|
267 |
, ("CvENODEUSERSCRIPTS", 'C.cvEnodeuserscriptsCode) |
|
268 |
, ("CvENODEFILESTORAGEPATHS", 'C.cvEnodefilestoragepathsCode) |
|
269 |
, ("CvENODEFILESTORAGEPATHUNUSABLE", 'C.cvEnodefilestoragepathunusableCode) |
|
269 | 270 |
]) |
270 | 271 |
$(THH.makeJSONInstance ''CVErrorCode) |
271 | 272 |
|
b/test/py/ganeti.storage.filestorage_unittest.py | ||
---|---|---|
21 | 21 |
|
22 | 22 |
"""Script for unittesting the ganeti.storage.file module""" |
23 | 23 |
|
24 |
|
|
24 |
import os |
|
25 |
import shutil |
|
26 |
import tempfile |
|
25 | 27 |
import unittest |
26 | 28 |
|
27 | 29 |
from ganeti import errors |
... | ... | |
43 | 45 |
"""Smoke test run on a directory that exists for sure. |
44 | 46 |
|
45 | 47 |
""" |
46 |
info = filestorage.GetFileStorageSpaceInfo("/") |
|
48 |
filestorage.GetFileStorageSpaceInfo("/") |
|
49 |
|
|
50 |
|
|
51 |
class TestCheckFileStoragePath(unittest.TestCase): |
|
52 |
def _WriteAllowedFile(self, allowed_paths_filename, allowed_paths): |
|
53 |
allowed_paths_file = open(allowed_paths_filename, 'w') |
|
54 |
allowed_paths_file.write('\n'.join(allowed_paths)) |
|
55 |
allowed_paths_file.close() |
|
56 |
|
|
57 |
def setUp(self): |
|
58 |
self.tmpdir = tempfile.mkdtemp() |
|
59 |
self.allowed_paths = [os.path.join(self.tmpdir, "allowed")] |
|
60 |
for path in self.allowed_paths: |
|
61 |
os.mkdir(path) |
|
62 |
self.allowed_paths_filename = os.path.join(self.tmpdir, "allowed-path-file") |
|
63 |
self._WriteAllowedFile(self.allowed_paths_filename, self.allowed_paths) |
|
64 |
|
|
65 |
def tearDown(self): |
|
66 |
shutil.rmtree(self.tmpdir) |
|
67 |
|
|
68 |
def testCheckFileStoragePathExistance(self): |
|
69 |
filestorage._CheckFileStoragePathExistance(self.tmpdir) |
|
70 |
|
|
71 |
def testCheckFileStoragePathExistanceFail(self): |
|
72 |
path = os.path.join(self.tmpdir, "does/not/exist") |
|
73 |
self.assertRaises(errors.FileStoragePathError, |
|
74 |
filestorage._CheckFileStoragePathExistance, path) |
|
75 |
|
|
76 |
def testCheckFileStoragePathNotWritable(self): |
|
77 |
path = os.path.join(self.tmpdir, "isnotwritable/") |
|
78 |
os.mkdir(path) |
|
79 |
os.chmod(path, 0) |
|
80 |
self.assertRaises(errors.FileStoragePathError, |
|
81 |
filestorage._CheckFileStoragePathExistance, path) |
|
82 |
os.chmod(path, 777) |
|
83 |
|
|
84 |
def testCheckFileStoragePath(self): |
|
85 |
path = os.path.join(self.allowed_paths[0], "allowedsubdir") |
|
86 |
os.mkdir(path) |
|
87 |
result = filestorage.CheckFileStoragePath( |
|
88 |
path, _allowed_paths_file=self.allowed_paths_filename) |
|
89 |
self.assertEqual(None, result) |
|
90 |
|
|
91 |
def testCheckFileStoragePathNotAllowed(self): |
|
92 |
path = os.path.join(self.tmpdir, "notallowed") |
|
93 |
result = filestorage.CheckFileStoragePath( |
|
94 |
path, _allowed_paths_file=self.allowed_paths_filename) |
|
95 |
self.assertTrue("not acceptable" in result) |
|
47 | 96 |
|
48 | 97 |
|
49 | 98 |
if __name__ == "__main__": |
Also available in: Unified diff