4 # Copyright (C) 2011 Google Inc.
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.
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.
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
21 """Script to ensure permissions on files/dirs are accurate.
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
43 QUEUE_DIR) = range(1, 4)
45 ALL_TYPES = frozenset([
52 class EnsureError(errors.GenericError):
53 """Top-level error class related to this script.
58 def EnsurePermission(path, mode, uid=-1, gid=-1, must_exist=True,
59 _chmod_fn=os.chmod, _chown_fn=os.chown):
60 """Ensures that given path has given mode.
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)
71 logging.debug("Checking %s", path)
75 if max(uid, gid) > -1:
76 _chown_fn(path, uid, gid)
77 except EnvironmentError, err:
78 if err.errno == errno.ENOENT:
80 raise EnsureError("Path %s does not exists, but should" % path)
82 raise EnsureError("Error while changing permission on %s: %s" %
86 def EnsureDir(path, mode, uid, gid, _stat_fn=os.lstat, _mkdir_fn=os.mkdir,
87 _ensure_fn=EnsurePermission):
88 """Ensures that given path is a dir and has given mode, uid and gid set.
90 @param path: The path to the file
91 @param mode: The mode of the file
92 @param uid: The uid of the owner of this file
93 @param gid: The gid of the owner of this file
94 @param _stat_fn: Stat function to use (unittest only)
95 @param _mkdir_fn: mkdir function to use (unittest only)
96 @param _ensure_fn: ensure function to use (unittest only)
99 logging.debug("Checking directory %s", path)
101 # We don't want to follow symlinks
102 st_mode = _stat_fn(path)[stat.ST_MODE]
104 if not stat.S_ISDIR(st_mode):
105 raise EnsureError("Path %s is expected to be a directory, but it's not" %
107 except EnvironmentError, err:
108 if err.errno == errno.ENOENT:
111 raise EnsureError("Error while do a stat() on %s: %s" % (path, err))
113 _ensure_fn(path, mode, uid=uid, gid=gid)
116 def RecursiveEnsure(path, uid, gid, dir_perm, file_perm):
117 """Ensures permissions recursively down a directory.
119 This functions walks the path and sets permissions accordingly.
121 @param path: The absolute path to walk
122 @param uid: The uid used as owner
123 @param gid: The gid used as group
124 @param dir_perm: The permission bits set for directories
125 @param file_perm: The permission bits set for files
128 assert os.path.isabs(path), "Path %s is not absolute" % path
129 assert os.path.isdir(path), "Path %s is not a dir" % path
131 logging.debug("Recursively processing %s", path)
133 for root, dirs, files in os.walk(path):
135 EnsurePermission(os.path.join(root, subdir), dir_perm, uid=uid, gid=gid)
137 for filename in files:
138 EnsurePermission(os.path.join(root, filename), file_perm, uid=uid,
142 def EnsureQueueDir(path, mode, uid, gid):
143 """Sets the correct permissions on all job files in the queue.
145 @param path: Directory path
146 @param mode: Wanted file mode
147 @param uid: Wanted user ID
148 @param gid: Wanted group ID
151 for filename in utils.ListVisibleFiles(path):
152 if constants.JOB_FILE_RE.match(filename):
153 EnsurePermission(utils.PathJoin(path, filename), mode, uid=uid, gid=gid)
156 def ProcessPath(path):
157 """Processes a path component.
159 @param path: A tuple of the path component to process
162 (pathname, pathtype, mode, uid, gid) = path[0:5]
164 assert pathtype in ALL_TYPES
166 if pathtype in (DIR, QUEUE_DIR):
167 # No additional parameters
168 assert len(path[5:]) == 0
170 EnsureDir(pathname, mode, uid, gid)
171 elif pathtype == QUEUE_DIR:
172 EnsureQueueDir(pathname, mode, uid, gid)
173 elif pathtype == FILE:
174 (must_exist, ) = path[5:]
175 EnsurePermission(pathname, mode, uid=uid, gid=gid, must_exist=must_exist)
179 """Returns a tuple of path objects to process.
182 getent = runtime.GetEnts()
183 masterd_log = constants.DAEMONS_LOGFILES[constants.MASTERD]
184 noded_log = constants.DAEMONS_LOGFILES[constants.NODED]
185 confd_log = constants.DAEMONS_LOGFILES[constants.CONFD]
186 rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI]
188 rapi_dir = os.path.join(constants.DATA_DIR, "rapi")
191 (constants.DATA_DIR, DIR, 0755, getent.masterd_uid,
193 (constants.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640,
194 getent.masterd_uid, getent.masterd_gid, False),
195 (constants.CLUSTER_CONF_FILE, FILE, 0640, getent.masterd_uid,
196 getent.confd_gid, False),
197 (constants.CONFD_HMAC_KEY, FILE, 0440, getent.confd_uid,
198 getent.masterd_gid, False),
199 (constants.SSH_KNOWN_HOSTS_FILE, FILE, 0644, getent.masterd_uid,
200 getent.masterd_gid, False),
201 (constants.RAPI_CERT_FILE, FILE, 0440, getent.rapi_uid,
202 getent.masterd_gid, False),
203 (constants.NODED_CERT_FILE, FILE, 0440, getent.masterd_uid,
204 getent.masterd_gid, False),
207 ss = ssconf.SimpleStore()
208 for ss_path in ss.GetFileList():
209 paths.append((ss_path, FILE, constants.SS_FILE_PERMS,
210 getent.noded_uid, 0, False))
213 (constants.QUEUE_DIR, DIR, 0700, getent.masterd_uid,
215 (constants.QUEUE_DIR, QUEUE_DIR, 0600, getent.masterd_uid,
217 (constants.JOB_QUEUE_LOCK_FILE, FILE, 0600,
218 getent.masterd_uid, getent.masterd_gid, False),
219 (constants.JOB_QUEUE_SERIAL_FILE, FILE, 0600,
220 getent.masterd_uid, getent.masterd_gid, False),
221 (constants.JOB_QUEUE_ARCHIVE_DIR, DIR, 0700,
222 getent.masterd_uid, getent.masterd_gid),
223 (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
224 (constants.RAPI_USERS_FILE, FILE, 0640, getent.rapi_uid,
225 getent.masterd_gid, False),
226 (constants.RUN_GANETI_DIR, DIR, 0775, getent.masterd_uid,
228 (constants.SOCKET_DIR, DIR, 0750, getent.masterd_uid,
230 (constants.MASTER_SOCKET, FILE, 0770, getent.masterd_uid,
231 getent.daemons_gid, False),
232 (constants.BDEV_CACHE_DIR, DIR, 0755, getent.noded_uid,
234 (constants.UIDPOOL_LOCKDIR, DIR, 0750, getent.noded_uid,
236 (constants.DISK_LINKS_DIR, DIR, 0755, getent.noded_uid,
238 (constants.CRYPTO_KEYS_DIR, DIR, 0700, getent.noded_uid,
240 (constants.IMPORT_EXPORT_DIR, DIR, 0755, getent.noded_uid,
242 (constants.LOG_DIR, DIR, 0770, getent.masterd_uid,
244 (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid,
246 (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False),
247 (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False),
248 (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False),
249 (constants.LOG_OS_DIR, DIR, 0750, getent.masterd_uid,
256 def SetupLogging(opts):
257 """Configures the logging module.
260 formatter = logging.Formatter("%(asctime)s: %(message)s")
262 stderr_handler = logging.StreamHandler()
263 stderr_handler.setFormatter(formatter)
265 stderr_handler.setLevel(logging.NOTSET)
267 stderr_handler.setLevel(logging.INFO)
269 stderr_handler.setLevel(logging.WARNING)
271 root_logger = logging.getLogger("")
272 root_logger.setLevel(logging.NOTSET)
273 root_logger.addHandler(stderr_handler)
277 """Parses the options passed to the program.
279 @return: Options and arguments
282 program = os.path.basename(sys.argv[0])
284 parser = optparse.OptionParser(usage="%%prog [--full-run]",
286 parser.add_option(cli.DEBUG_OPT)
287 parser.add_option(cli.VERBOSE_OPT)
288 parser.add_option("--full-run", "-f", dest="full_run", action="store_true",
289 default=False, help=("Make a full run and collect"
290 " additional files (time consuming)"))
292 return parser.parse_args()
299 (opts, _) = ParseOptions()
304 logging.info("Running in full mode")
306 getent = runtime.GetEnts()
309 for path in GetPaths():
313 RecursiveEnsure(constants.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid,
314 getent.masterd_gid, 0700, 0600)
315 except EnsureError, err:
316 logging.error("An error occurred while setting permissions: %s", err)
317 return constants.EXIT_FAILURE
319 return constants.EXIT_SUCCESS