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.
32 from ganeti import constants
33 from ganeti import errors
34 from ganeti import runtime
35 from ganeti import ssconf
36 from ganeti import utils
41 QUEUE_DIR) = range(1, 4)
43 ALL_TYPES = frozenset([
50 class EnsureError(errors.GenericError):
51 """Top-level error class related to this script.
56 def EnsurePermission(path, mode, uid=-1, gid=-1, must_exist=True,
57 _chmod_fn=os.chmod, _chown_fn=os.chown):
58 """Ensures that given path has given mode.
60 @param path: The path to the file
61 @param mode: The mode of the file
62 @param uid: The uid of the owner of this file
63 @param gid: The gid of the owner of this file
64 @param must_exist: Specifies if non-existance of path will be an error
65 @param _chmod_fn: chmod function to use (unittest only)
66 @param _chown_fn: chown function to use (unittest only)
72 if max(uid, gid) > -1:
73 _chown_fn(path, uid, gid)
74 except EnvironmentError, err:
75 if err.errno == errno.ENOENT:
77 raise EnsureError("Path %s does not exists, but should" % path)
79 raise EnsureError("Error while changing permission on %s: %s" %
83 def EnsureDir(path, mode, uid, gid, _stat_fn=os.lstat, _mkdir_fn=os.mkdir,
84 _ensure_fn=EnsurePermission):
85 """Ensures that given path is a dir and has given mode, uid and gid set.
87 @param path: The path to the file
88 @param mode: The mode of the file
89 @param uid: The uid of the owner of this file
90 @param gid: The gid of the owner of this file
91 @param _stat_fn: Stat function to use (unittest only)
92 @param _mkdir_fn: mkdir function to use (unittest only)
93 @param _ensure_fn: ensure function to use (unittest only)
97 # We don't want to follow symlinks
98 st_mode = _stat_fn(path)[stat.ST_MODE]
100 if not stat.S_ISDIR(st_mode):
101 raise EnsureError("Path %s is expected to be a directory, but it's not" %
103 except EnvironmentError, err:
104 if err.errno == errno.ENOENT:
107 raise EnsureError("Error while do a stat() on %s: %s" % (path, err))
109 _ensure_fn(path, mode, uid=uid, gid=gid)
112 def RecursiveEnsure(path, uid, gid, dir_perm, file_perm):
113 """Ensures permissions recursively down a directory.
115 This functions walks the path and sets permissions accordingly.
117 @param path: The absolute path to walk
118 @param uid: The uid used as owner
119 @param gid: The gid used as group
120 @param dir_perm: The permission bits set for directories
121 @param file_perm: The permission bits set for files
124 assert os.path.isabs(path), "Path %s is not absolute" % path
125 assert os.path.isdir(path), "Path %s is not a dir" % path
127 for root, dirs, files in os.walk(path):
129 EnsurePermission(os.path.join(root, subdir), dir_perm, uid=uid, gid=gid)
131 for filename in files:
132 EnsurePermission(os.path.join(root, filename), file_perm, uid=uid,
136 def EnsureQueueDir(path, mode, uid, gid):
137 """Sets the correct permissions on all job files in the queue.
139 @param path: Directory path
140 @param mode: Wanted file mode
141 @param uid: Wanted user ID
142 @param gid: Wanted group ID
145 for filename in utils.ListVisibleFiles(path):
146 if constants.JOB_FILE_RE.match(filename):
147 EnsurePermission(utils.PathJoin(path, filename), mode, uid=uid, gid=gid)
150 def ProcessPath(path):
151 """Processes a path component.
153 @param path: A tuple of the path component to process
156 (pathname, pathtype, mode, uid, gid) = path[0:5]
158 assert pathtype in ALL_TYPES
160 if pathtype in (DIR, QUEUE_DIR):
161 # No additional parameters
162 assert len(path[5:]) == 0
164 EnsureDir(pathname, mode, uid, gid)
165 elif pathtype == QUEUE_DIR:
166 EnsureQueueDir(pathname, mode, uid, gid)
167 elif pathtype == FILE:
168 (must_exist, ) = path[5:]
169 EnsurePermission(pathname, mode, uid=uid, gid=gid, must_exist=must_exist)
173 """Returns a tuple of path objects to process.
176 getent = runtime.GetEnts()
177 masterd_log = constants.DAEMONS_LOGFILES[constants.MASTERD]
178 noded_log = constants.DAEMONS_LOGFILES[constants.NODED]
179 confd_log = constants.DAEMONS_LOGFILES[constants.CONFD]
180 rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI]
182 rapi_dir = os.path.join(constants.DATA_DIR, "rapi")
185 (constants.DATA_DIR, DIR, 0755, getent.masterd_uid,
187 (constants.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640,
188 getent.masterd_uid, getent.masterd_gid, False),
189 (constants.CLUSTER_CONF_FILE, FILE, 0640, getent.masterd_uid,
190 getent.confd_gid, False),
191 (constants.CONFD_HMAC_KEY, FILE, 0440, getent.confd_uid,
192 getent.masterd_gid, False),
193 (constants.SSH_KNOWN_HOSTS_FILE, FILE, 0644, getent.masterd_uid,
194 getent.masterd_gid, False),
195 (constants.RAPI_CERT_FILE, FILE, 0440, getent.rapi_uid,
196 getent.masterd_gid, False),
197 (constants.NODED_CERT_FILE, FILE, 0440, getent.masterd_uid,
198 getent.masterd_gid, False),
201 ss = ssconf.SimpleStore()
202 for ss_path in ss.GetFileList():
203 paths.append((ss_path, FILE, constants.SS_FILE_PERMS,
204 getent.noded_uid, 0, False))
207 (constants.QUEUE_DIR, DIR, 0700, getent.masterd_uid,
209 (constants.QUEUE_DIR, QUEUE_DIR, 0600, getent.masterd_uid,
211 (constants.JOB_QUEUE_LOCK_FILE, FILE, 0600,
212 getent.masterd_uid, getent.masterd_gid, False),
213 (constants.JOB_QUEUE_SERIAL_FILE, FILE, 0600,
214 getent.masterd_uid, getent.masterd_gid, False),
215 (constants.JOB_QUEUE_ARCHIVE_DIR, DIR, 0700,
216 getent.masterd_uid, getent.masterd_gid),
217 (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
218 (constants.RAPI_USERS_FILE, FILE, 0640, getent.rapi_uid,
219 getent.masterd_gid, False),
220 (constants.RUN_GANETI_DIR, DIR, 0775, getent.masterd_uid,
222 (constants.SOCKET_DIR, DIR, 0750, getent.masterd_uid,
224 (constants.MASTER_SOCKET, FILE, 0770, getent.masterd_uid,
225 getent.daemons_gid, False),
226 (constants.BDEV_CACHE_DIR, DIR, 0755, getent.noded_uid,
228 (constants.UIDPOOL_LOCKDIR, DIR, 0750, getent.noded_uid,
230 (constants.DISK_LINKS_DIR, DIR, 0755, getent.noded_uid,
232 (constants.CRYPTO_KEYS_DIR, DIR, 0700, getent.noded_uid,
234 (constants.IMPORT_EXPORT_DIR, DIR, 0755, getent.noded_uid,
236 (constants.LOG_DIR, DIR, 0770, getent.masterd_uid,
238 (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid,
240 (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False),
241 (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False),
242 (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False),
243 (constants.LOG_OS_DIR, DIR, 0750, getent.masterd_uid,
251 """Parses the options passed to the program.
253 @return: Options and arguments
256 program = os.path.basename(sys.argv[0])
258 parser = optparse.OptionParser(usage="%%prog [--full-run]",
260 parser.add_option("--full-run", "-f", dest="full_run", action="store_true",
261 default=False, help=("Make a full run and collect"
262 " additional files (time consuming)"))
264 return parser.parse_args()
271 getent = runtime.GetEnts()
272 (opts, _) = ParseOptions()
275 for path in GetPaths():
279 RecursiveEnsure(constants.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid,
280 getent.masterd_gid, 0700, 0600)
281 except EnsureError, err:
282 print >> sys.stderr, "An error occurred while ensure permissions:", err
283 return constants.EXIT_FAILURE
285 return constants.EXIT_SUCCESS