Statistics
| Branch: | Tag: | Revision:

root / lib / storage / filestorage.py @ 355d1f32

History | View | Annotate | Download (6.4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2013 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21

    
22
"""File storage functions.
23

24
"""
25

    
26
import logging
27
import os
28

    
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
34

    
35

    
36
def GetFileStorageSpaceInfo(path):
37
  """Retrieves the free and total space of the device where the file is
38
     located.
39

40
     @type path: string
41
     @param path: Path of the file whose embracing device's capacity is
42
       reported.
43
     @return: a dictionary containing 'vg_size' and 'vg_free' given in MebiBytes
44

45
  """
46
  try:
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,
51
            "name": path,
52
            "storage_size": size,
53
            "storage_free": free}
54
  except OSError, e:
55
    raise errors.CommandError("Failed to retrieve file system information about"
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, exact_match_ok=False):
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
  @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
122

123
  """
124
  if not os.path.isabs(path):
125
    raise errors.FileStoragePathError("File storage path must be absolute,"
126
                                      " got '%s'" % path)
127

    
128
  for i in allowed:
129
    if not os.path.isabs(i):
130
      logging.info("Ignoring relative path '%s' for file storage", i)
131
      continue
132

    
133
    if exact_match_ok:
134
      if os.path.normpath(i) == os.path.normpath(path):
135
        break
136

    
137
    if utils.IsBelowDir(i, path):
138
      break
139
  else:
140
    raise errors.FileStoragePathError("Path '%s' is not acceptable for file"
141
                                      " storage" % path)
142

    
143

    
144
def _LoadAllowedFileStoragePaths(filename):
145
  """Loads file containing allowed file storage paths.
146

147
  @rtype: list
148
  @return: List of allowed paths (can be an empty list)
149

150
  """
151
  try:
152
    contents = utils.ReadFile(filename)
153
  except EnvironmentError:
154
    return []
155
  else:
156
    return utils.FilterEmptyLinesAndComments(contents)
157

    
158

    
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.
163

164
  @type path: string
165
  @param path: Path to check
166
  @raise errors.FileStoragePathError: If the path is not allowed
167

168
  """
169
  allowed = _LoadAllowedFileStoragePaths(_filename)
170
  if not allowed:
171
    raise errors.FileStoragePathError("No paths are valid or path file '%s'"
172
                                      " was not accessible." % _filename)
173

    
174
  if _ComputeWrongFileStoragePaths([path]):
175
    raise errors.FileStoragePathError("Path '%s' uses a forbidden prefix" %
176
                                      path)
177

    
178
  _CheckFileStoragePath(path, allowed, exact_match_ok=exact_match_ok)
179

    
180

    
181
def _CheckFileStoragePathExistance(path):
182
  """Checks whether the given path is usable on the file system.
183

184
  This checks wether the path is existing, a directory and writable.
185

186
  @type path: string
187
  @param path: path to check
188

189
  """
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)
195

    
196

    
197
def CheckFileStoragePath(
198
    path, _allowed_paths_file=pathutils.FILE_STORAGE_PATHS_FILE):
199
  """Checks whether the path exists and is acceptable to use.
200

201
  Can be used for any file-based storage, for example shared-file storage.
202

203
  @type path: string
204
  @param path: path to check
205
  @rtype: string
206
  @returns: error message if the path is not ready to use
207

208
  """
209
  try:
210
    CheckFileStoragePathAcceptance(path, _filename=_allowed_paths_file,
211
                                   exact_match_ok=True)
212
  except errors.FileStoragePathError as e:
213
    return str(e)
214
  if not os.path.isdir(path):
215
    return "Path '%s' is not exisiting or not a directory." % path
216
  if not os.access(path, os.W_OK):
217
    return "Path '%s' is not writable" % path