Package ganeti :: Package tools :: Module ensure_dirs
[hide private]
[frames] | no frames]

Source Code for Module ganeti.tools.ensure_dirs

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2011 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  """Script to ensure permissions on files/dirs are accurate. 
 22   
 23  """ 
 24   
 25  import errno 
 26  import os 
 27  import os.path 
 28  import optparse 
 29  import sys 
 30  import stat 
 31  import logging 
 32   
 33  from ganeti import constants 
 34  from ganeti import errors 
 35  from ganeti import runtime 
 36  from ganeti import ssconf 
 37  from ganeti import utils 
 38  from ganeti import cli 
 39   
 40   
 41  (DIR, 
 42   FILE, 
 43   QUEUE_DIR) = range(1, 4) 
 44   
 45  ALL_TYPES = frozenset([ 
 46    DIR, 
 47    FILE, 
 48    QUEUE_DIR, 
 49    ]) 
 50   
 51   
52 -class EnsureError(errors.GenericError):
53 """Top-level error class related to this script. 54 55 """
56 57
58 -def EnsurePermission(path, mode, uid=-1, gid=-1, must_exist=True, 59 _chmod_fn=os.chmod, _chown_fn=os.chown, _stat_fn=os.stat):
60 """Ensures that given path has given mode. 61 62 @param path: The path to the file 63 @param mode: The mode of the file 64 @param uid: The uid of the owner of this file 65 @param gid: The gid of the owner of this file 66 @param must_exist: Specifies if non-existance of path will be an error 67 @param _chmod_fn: chmod function to use (unittest only) 68 @param _chown_fn: chown function to use (unittest only) 69 70 """ 71 logging.debug("Checking %s", path) 72 try: 73 st = _stat_fn(path) 74 75 fmode = stat.S_IMODE(st[stat.ST_MODE]) 76 if fmode != mode: 77 logging.debug("Changing mode of %s from %#o to %#o", path, fmode, mode) 78 _chmod_fn(path, mode) 79 80 if max(uid, gid) > -1: 81 fuid = st[stat.ST_UID] 82 fgid = st[stat.ST_GID] 83 if fuid != uid or fgid != gid: 84 logging.debug("Changing owner of %s from UID %s/GID %s to" 85 " UID %s/GID %s", path, fuid, fgid, uid, gid) 86 _chown_fn(path, uid, gid) 87 except EnvironmentError, err: 88 if err.errno == errno.ENOENT: 89 if must_exist: 90 raise EnsureError("Path %s should exist, but does not" % path) 91 else: 92 raise EnsureError("Error while changing permissions on %s: %s" % 93 (path, err))
94 95
96 -def EnsureDir(path, mode, uid, gid, _lstat_fn=os.lstat, _mkdir_fn=os.mkdir, 97 _ensure_fn=EnsurePermission):
98 """Ensures that given path is a dir and has given mode, uid and gid set. 99 100 @param path: The path to the file 101 @param mode: The mode of the file 102 @param uid: The uid of the owner of this file 103 @param gid: The gid of the owner of this file 104 @param _lstat_fn: Stat function to use (unittest only) 105 @param _mkdir_fn: mkdir function to use (unittest only) 106 @param _ensure_fn: ensure function to use (unittest only) 107 108 """ 109 logging.debug("Checking directory %s", path) 110 try: 111 # We don't want to follow symlinks 112 st = _lstat_fn(path) 113 except EnvironmentError, err: 114 if err.errno != errno.ENOENT: 115 raise EnsureError("stat(2) on %s failed: %s" % (path, err)) 116 _mkdir_fn(path) 117 else: 118 if not stat.S_ISDIR(st[stat.ST_MODE]): 119 raise EnsureError("Path %s is expected to be a directory, but isn't" % 120 path) 121 122 _ensure_fn(path, mode, uid=uid, gid=gid)
123 124
125 -def RecursiveEnsure(path, uid, gid, dir_perm, file_perm):
126 """Ensures permissions recursively down a directory. 127 128 This functions walks the path and sets permissions accordingly. 129 130 @param path: The absolute path to walk 131 @param uid: The uid used as owner 132 @param gid: The gid used as group 133 @param dir_perm: The permission bits set for directories 134 @param file_perm: The permission bits set for files 135 136 """ 137 assert os.path.isabs(path), "Path %s is not absolute" % path 138 assert os.path.isdir(path), "Path %s is not a dir" % path 139 140 logging.debug("Recursively processing %s", path) 141 142 for root, dirs, files in os.walk(path): 143 for subdir in dirs: 144 EnsurePermission(os.path.join(root, subdir), dir_perm, uid=uid, gid=gid) 145 146 for filename in files: 147 EnsurePermission(os.path.join(root, filename), file_perm, uid=uid, 148 gid=gid)
149 150
151 -def EnsureQueueDir(path, mode, uid, gid):
152 """Sets the correct permissions on all job files in the queue. 153 154 @param path: Directory path 155 @param mode: Wanted file mode 156 @param uid: Wanted user ID 157 @param gid: Wanted group ID 158 159 """ 160 for filename in utils.ListVisibleFiles(path): 161 if constants.JOB_FILE_RE.match(filename): 162 EnsurePermission(utils.PathJoin(path, filename), mode, uid=uid, gid=gid)
163 164
165 -def ProcessPath(path):
166 """Processes a path component. 167 168 @param path: A tuple of the path component to process 169 170 """ 171 (pathname, pathtype, mode, uid, gid) = path[0:5] 172 173 assert pathtype in ALL_TYPES 174 175 if pathtype in (DIR, QUEUE_DIR): 176 # No additional parameters 177 assert len(path[5:]) == 0 178 if pathtype == DIR: 179 EnsureDir(pathname, mode, uid, gid) 180 elif pathtype == QUEUE_DIR: 181 EnsureQueueDir(pathname, mode, uid, gid) 182 elif pathtype == FILE: 183 (must_exist, ) = path[5:] 184 EnsurePermission(pathname, mode, uid=uid, gid=gid, must_exist=must_exist)
185 186
187 -def GetPaths():
188 """Returns a tuple of path objects to process. 189 190 """ 191 getent = runtime.GetEnts() 192 masterd_log = constants.DAEMONS_LOGFILES[constants.MASTERD] 193 noded_log = constants.DAEMONS_LOGFILES[constants.NODED] 194 confd_log = constants.DAEMONS_LOGFILES[constants.CONFD] 195 rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI] 196 197 rapi_dir = os.path.join(constants.DATA_DIR, "rapi") 198 199 paths = [ 200 (constants.DATA_DIR, DIR, 0755, getent.masterd_uid, 201 getent.masterd_gid), 202 (constants.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640, 203 getent.masterd_uid, getent.masterd_gid, False), 204 (constants.CLUSTER_CONF_FILE, FILE, 0640, getent.masterd_uid, 205 getent.confd_gid, False), 206 (constants.CONFD_HMAC_KEY, FILE, 0440, getent.confd_uid, 207 getent.masterd_gid, False), 208 (constants.SSH_KNOWN_HOSTS_FILE, FILE, 0644, getent.masterd_uid, 209 getent.masterd_gid, False), 210 (constants.RAPI_CERT_FILE, FILE, 0440, getent.rapi_uid, 211 getent.masterd_gid, False), 212 (constants.NODED_CERT_FILE, FILE, 0440, getent.masterd_uid, 213 getent.masterd_gid, False), 214 ] 215 216 ss = ssconf.SimpleStore() 217 for ss_path in ss.GetFileList(): 218 paths.append((ss_path, FILE, constants.SS_FILE_PERMS, 219 getent.noded_uid, 0, False)) 220 221 paths.extend([ 222 (constants.QUEUE_DIR, DIR, 0700, getent.masterd_uid, 223 getent.masterd_gid), 224 (constants.QUEUE_DIR, QUEUE_DIR, 0600, getent.masterd_uid, 225 getent.masterd_gid), 226 (constants.JOB_QUEUE_LOCK_FILE, FILE, 0600, 227 getent.masterd_uid, getent.masterd_gid, False), 228 (constants.JOB_QUEUE_SERIAL_FILE, FILE, 0600, 229 getent.masterd_uid, getent.masterd_gid, False), 230 (constants.JOB_QUEUE_VERSION_FILE, FILE, 0600, 231 getent.masterd_uid, getent.masterd_gid, False), 232 (constants.JOB_QUEUE_ARCHIVE_DIR, DIR, 0700, 233 getent.masterd_uid, getent.masterd_gid), 234 (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid), 235 (constants.RAPI_USERS_FILE, FILE, 0640, getent.rapi_uid, 236 getent.masterd_gid, False), 237 (constants.RUN_GANETI_DIR, DIR, 0775, getent.masterd_uid, 238 getent.daemons_gid), 239 (constants.SOCKET_DIR, DIR, 0750, getent.masterd_uid, 240 getent.daemons_gid), 241 (constants.MASTER_SOCKET, FILE, 0770, getent.masterd_uid, 242 getent.daemons_gid, False), 243 (constants.BDEV_CACHE_DIR, DIR, 0755, getent.noded_uid, 244 getent.masterd_gid), 245 (constants.UIDPOOL_LOCKDIR, DIR, 0750, getent.noded_uid, 246 getent.masterd_gid), 247 (constants.DISK_LINKS_DIR, DIR, 0755, getent.noded_uid, 248 getent.masterd_gid), 249 (constants.CRYPTO_KEYS_DIR, DIR, 0700, getent.noded_uid, 250 getent.masterd_gid), 251 (constants.IMPORT_EXPORT_DIR, DIR, 0755, getent.noded_uid, 252 getent.masterd_gid), 253 (constants.LOG_DIR, DIR, 0770, getent.masterd_uid, 254 getent.daemons_gid), 255 (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid, 256 False), 257 (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False), 258 (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False), 259 (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False), 260 (constants.LOG_OS_DIR, DIR, 0750, getent.masterd_uid, 261 getent.daemons_gid), 262 ]) 263 264 return tuple(paths)
265 266
267 -def SetupLogging(opts):
268 """Configures the logging module. 269 270 """ 271 formatter = logging.Formatter("%(asctime)s: %(message)s") 272 273 stderr_handler = logging.StreamHandler() 274 stderr_handler.setFormatter(formatter) 275 if opts.debug: 276 stderr_handler.setLevel(logging.NOTSET) 277 elif opts.verbose: 278 stderr_handler.setLevel(logging.INFO) 279 else: 280 stderr_handler.setLevel(logging.WARNING) 281 282 root_logger = logging.getLogger("") 283 root_logger.setLevel(logging.NOTSET) 284 root_logger.addHandler(stderr_handler)
285 286
287 -def ParseOptions():
288 """Parses the options passed to the program. 289 290 @return: Options and arguments 291 292 """ 293 program = os.path.basename(sys.argv[0]) 294 295 parser = optparse.OptionParser(usage="%%prog [--full-run]", 296 prog=program) 297 parser.add_option(cli.DEBUG_OPT) 298 parser.add_option(cli.VERBOSE_OPT) 299 parser.add_option("--full-run", "-f", dest="full_run", action="store_true", 300 default=False, help=("Make a full run and set permissions" 301 " on archived jobs (time consuming)")) 302 303 return parser.parse_args()
304 305
306 -def Main():
307 """Main routine. 308 309 """ 310 (opts, _) = ParseOptions() 311 312 SetupLogging(opts) 313 314 if opts.full_run: 315 logging.info("Running in full mode") 316 317 getent = runtime.GetEnts() 318 319 try: 320 for path in GetPaths(): 321 ProcessPath(path) 322 323 if opts.full_run: 324 RecursiveEnsure(constants.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid, 325 getent.masterd_gid, 0700, 0600) 326 except EnsureError, err: 327 logging.error("An error occurred while setting permissions: %s", err) 328 return constants.EXIT_FAILURE 329 330 return constants.EXIT_SUCCESS
331