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