1 # Copyright (C) 2011 Google Inc.
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 """Script to ensure permissions on files/dirs are accurate.
29 from ganeti import constants
30 from ganeti import errors
31 from ganeti import runtime
32 from ganeti import ssconf
35 (DIR, FILE) = range(2)
36 ALL_TYPES = frozenset([DIR, FILE])
39 class EnsureError(errors.GenericError):
40 """Top-level error class related to this script.
45 def EnsurePermission(path, mode, uid=-1, gid=-1, must_exist=True,
46 _chmod_fn=os.chmod, _chown_fn=os.chown):
47 """Ensures that given path has given mode.
49 @param path: The path to the file
50 @param mode: The mode of the file
51 @param uid: The uid of the owner of this file
52 @param gid: The gid of the owner of this file
53 @param must_exist: Specifies if non-existance of path will be an error
54 @param _chmod_fn: chmod function to use (unittest only)
55 @param _chown_fn: chown function to use (unittest only)
61 if max(uid, gid) > -1:
62 _chown_fn(path, uid, gid)
63 except EnvironmentError, err:
64 if err.errno == errno.ENOENT:
66 raise EnsureError("Path %s does not exists, but should" % path)
68 raise EnsureError("Error while changing permission on %s: %s" %
72 def EnsureDir(path, mode, uid, gid, _stat_fn=os.lstat, _mkdir_fn=os.mkdir,
73 _ensure_fn=EnsurePermission):
74 """Ensures that given path is a dir and has given mode, uid and gid set.
76 @param path: The path to the file
77 @param mode: The mode of the file
78 @param uid: The uid of the owner of this file
79 @param gid: The gid of the owner of this file
80 @param _stat_fn: Stat function to use (unittest only)
81 @param _mkdir_fn: mkdir function to use (unittest only)
82 @param _ensure_fn: ensure function to use (unittest only)
86 # We don't want to follow symlinks
87 st_mode = _stat_fn(path)[stat.ST_MODE]
89 if not stat.S_ISDIR(st_mode):
90 raise EnsureError("Path %s is expected to be a directory, but it's not" %
92 except EnvironmentError, err:
93 if err.errno == errno.ENOENT:
96 raise EnsureError("Error while do a stat() on %s: %s" % (path, err))
98 _ensure_fn(path, mode, uid=uid, gid=gid)
101 def RecursiveEnsure(path, uid, gid, dir_perm, file_perm):
102 """Ensures permissions recursively down a directory.
104 This functions walks the path and sets permissions accordingly.
106 @param path: The absolute path to walk
107 @param uid: The uid used as owner
108 @param gid: The gid used as group
109 @param dir_perm: The permission bits set for directories
110 @param file_perm: The permission bits set for files
113 assert os.path.isabs(path), "Path %s is not absolute" % path
114 assert os.path.isdir(path), "Path %s is not a dir" % path
116 for root, dirs, files in os.walk(path):
118 EnsurePermission(os.path.join(root, subdir), dir_perm, uid=uid, gid=gid)
120 for filename in files:
121 EnsurePermission(os.path.join(root, filename), file_perm, uid=uid,
125 def ProcessPath(path):
126 """Processes a path component.
128 @param path: A tuple of the path component to process
131 (pathname, pathtype, mode, uid, gid) = path[0:5]
133 assert pathtype in ALL_TYPES
136 # No additional parameters
137 assert len(path[5:]) == 0
138 EnsureDir(pathname, mode, uid, gid)
139 elif pathtype == FILE:
140 (must_exist, ) = path[5:]
141 EnsurePermission(pathname, mode, uid=uid, gid=gid, must_exist=must_exist)
145 """Returns a tuple of path objects to process.
148 getent = runtime.GetEnts()
149 masterd_log = constants.DAEMONS_LOGFILES[constants.MASTERD]
150 noded_log = constants.DAEMONS_LOGFILES[constants.NODED]
151 confd_log = constants.DAEMONS_LOGFILES[constants.CONFD]
152 rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI]
154 rapi_dir = os.path.join(constants.DATA_DIR, "rapi")
157 (constants.DATA_DIR, DIR, 0755, getent.masterd_uid,
159 (constants.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640,
160 getent.masterd_uid, getent.masterd_gid, False),
161 (constants.CLUSTER_CONF_FILE, FILE, 0640, getent.masterd_uid,
162 getent.confd_gid, False),
163 (constants.CONFD_HMAC_KEY, FILE, 0440, getent.confd_uid,
164 getent.masterd_gid, False),
165 (constants.SSH_KNOWN_HOSTS_FILE, FILE, 0644, getent.masterd_uid,
166 getent.masterd_gid, False),
167 (constants.RAPI_CERT_FILE, FILE, 0440, getent.rapi_uid,
168 getent.masterd_gid, False),
169 (constants.NODED_CERT_FILE, FILE, 0440, getent.masterd_uid,
170 getent.masterd_gid, False),
173 ss = ssconf.SimpleStore()
174 for ss_path in ss.GetFileList():
175 paths.append((ss_path, FILE, constants.SS_FILE_PERMS,
176 getent.noded_uid, 0, False))
179 (constants.QUEUE_DIR, DIR, 0700, getent.masterd_uid,
181 (constants.JOB_QUEUE_SERIAL_FILE, FILE, 0600,
182 getent.masterd_uid, getent.masterd_gid, False),
183 (constants.JOB_QUEUE_ARCHIVE_DIR, DIR, 0700,
184 getent.masterd_uid, getent.masterd_gid),
185 (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
186 (constants.RAPI_USERS_FILE, FILE, 0640, getent.rapi_uid,
187 getent.masterd_gid, False),
188 (constants.RUN_GANETI_DIR, DIR, 0775, getent.masterd_uid,
190 (constants.SOCKET_DIR, DIR, 0750, getent.masterd_uid,
192 (constants.MASTER_SOCKET, FILE, 0770, getent.masterd_uid,
193 getent.daemons_gid, False),
194 (constants.BDEV_CACHE_DIR, DIR, 0755, getent.noded_uid,
196 (constants.UIDPOOL_LOCKDIR, DIR, 0750, getent.noded_uid,
198 (constants.DISK_LINKS_DIR, DIR, 0755, getent.noded_uid,
200 (constants.CRYPTO_KEYS_DIR, DIR, 0700, getent.noded_uid,
202 (constants.IMPORT_EXPORT_DIR, DIR, 0755, getent.noded_uid,
204 (constants.LOG_DIR, DIR, 0770, getent.masterd_uid,
206 (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid,
208 (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False),
209 (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False),
210 (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False),
211 (constants.LOG_OS_DIR, DIR, 0750, getent.masterd_uid,
219 """Parses the options passed to the program.
221 @return: Options and arguments
224 program = os.path.basename(sys.argv[0])
226 parser = optparse.OptionParser(usage="%%prog [--full-run]",
228 parser.add_option("--full-run", "-f", dest="full_run", action="store_true",
229 default=False, help=("Make a full run and collect"
230 " additional files (time consuming)"))
232 return parser.parse_args()
239 getent = runtime.GetEnts()
240 (opts, _) = ParseOptions()
243 for path in GetPaths():
247 RecursiveEnsure(constants.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid,
248 getent.masterd_gid, 0700, 0600)
249 except EnsureError, err:
250 print >> sys.stderr, "An error occurred while ensure permissions:", err
251 return constants.EXIT_FAILURE
253 return constants.EXIT_SUCCESS