root / lib / tools / ensure_dirs.py @ 0d2bf835
History | View | Annotate | Download (8 kB)
1 |
# Copyright (C) 2011 Google Inc.
|
---|---|
2 |
#
|
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.
|
7 |
#
|
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.
|
12 |
#
|
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
|
16 |
# 02110-1301, USA.
|
17 |
|
18 |
"""Script to ensure permissions on files/dirs are accurate.
|
19 |
|
20 |
"""
|
21 |
|
22 |
import errno |
23 |
import os |
24 |
import os.path |
25 |
import optparse |
26 |
import sys |
27 |
import stat |
28 |
|
29 |
from ganeti import constants |
30 |
from ganeti import errors |
31 |
from ganeti import runtime |
32 |
from ganeti import ssconf |
33 |
|
34 |
|
35 |
(DIR, FILE) = range(2) |
36 |
ALL_TYPES = frozenset([DIR, FILE])
|
37 |
|
38 |
|
39 |
class EnsureError(errors.GenericError): |
40 |
"""Top-level error class related to this script.
|
41 |
|
42 |
"""
|
43 |
|
44 |
|
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.
|
48 |
|
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)
|
56 |
|
57 |
"""
|
58 |
try:
|
59 |
_chmod_fn(path, mode) |
60 |
|
61 |
if max(uid, gid) > -1: |
62 |
_chown_fn(path, uid, gid) |
63 |
except EnvironmentError, err: |
64 |
if err.errno == errno.ENOENT:
|
65 |
if must_exist:
|
66 |
raise EnsureError("Path %s does not exists, but should" % path) |
67 |
else:
|
68 |
raise EnsureError("Error while changing permission on %s: %s" % |
69 |
(path, err)) |
70 |
|
71 |
|
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.
|
75 |
|
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)
|
83 |
|
84 |
"""
|
85 |
try:
|
86 |
# We don't want to follow symlinks
|
87 |
st_mode = _stat_fn(path)[stat.ST_MODE] |
88 |
|
89 |
if not stat.S_ISDIR(st_mode): |
90 |
raise EnsureError("Path %s is expected to be a directory, but it's not" % |
91 |
path) |
92 |
except EnvironmentError, err: |
93 |
if err.errno == errno.ENOENT:
|
94 |
_mkdir_fn(path) |
95 |
else:
|
96 |
raise EnsureError("Error while do a stat() on %s: %s" % (path, err)) |
97 |
|
98 |
_ensure_fn(path, mode, uid=uid, gid=gid) |
99 |
|
100 |
|
101 |
def RecursiveEnsure(path, uid, gid, dir_perm, file_perm): |
102 |
"""Ensures permissions recursively down a directory.
|
103 |
|
104 |
This functions walks the path and sets permissions accordingly.
|
105 |
|
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
|
111 |
|
112 |
"""
|
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 |
115 |
|
116 |
for root, dirs, files in os.walk(path): |
117 |
for subdir in dirs: |
118 |
EnsurePermission(os.path.join(root, subdir), dir_perm, uid=uid, gid=gid) |
119 |
|
120 |
for filename in files: |
121 |
EnsurePermission(os.path.join(root, filename), file_perm, uid=uid, |
122 |
gid=gid) |
123 |
|
124 |
|
125 |
def ProcessPath(path): |
126 |
"""Processes a path component.
|
127 |
|
128 |
@param path: A tuple of the path component to process
|
129 |
|
130 |
"""
|
131 |
(pathname, pathtype, mode, uid, gid) = path[0:5] |
132 |
|
133 |
assert pathtype in ALL_TYPES |
134 |
|
135 |
if pathtype == DIR:
|
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) |
142 |
|
143 |
|
144 |
def GetPaths(): |
145 |
"""Returns a tuple of path objects to process.
|
146 |
|
147 |
"""
|
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] |
153 |
|
154 |
rapi_dir = os.path.join(constants.DATA_DIR, "rapi")
|
155 |
|
156 |
paths = [ |
157 |
(constants.DATA_DIR, DIR, 0755, getent.masterd_uid,
|
158 |
getent.masterd_gid), |
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),
|
171 |
] |
172 |
|
173 |
ss = ssconf.SimpleStore() |
174 |
for ss_path in ss.GetFileList(): |
175 |
paths.append((ss_path, FILE, 0400, getent.noded_uid, 0, False)) |
176 |
|
177 |
paths.extend([ |
178 |
(constants.QUEUE_DIR, DIR, 0700, getent.masterd_uid,
|
179 |
getent.masterd_gid), |
180 |
(constants.JOB_QUEUE_SERIAL_FILE, FILE, 0600,
|
181 |
getent.masterd_uid, getent.masterd_gid, False),
|
182 |
(constants.JOB_QUEUE_ARCHIVE_DIR, DIR, 0700,
|
183 |
getent.masterd_uid, getent.masterd_gid), |
184 |
(rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
|
185 |
(constants.RAPI_USERS_FILE, FILE, 0640, getent.rapi_uid,
|
186 |
getent.masterd_gid, False),
|
187 |
(constants.RUN_GANETI_DIR, DIR, 0775, getent.masterd_uid,
|
188 |
getent.daemons_gid), |
189 |
(constants.SOCKET_DIR, DIR, 0750, getent.masterd_uid,
|
190 |
getent.daemons_gid), |
191 |
(constants.MASTER_SOCKET, FILE, 0770, getent.masterd_uid,
|
192 |
getent.daemons_gid, False),
|
193 |
(constants.BDEV_CACHE_DIR, DIR, 0755, getent.noded_uid,
|
194 |
getent.masterd_gid), |
195 |
(constants.UIDPOOL_LOCKDIR, DIR, 0750, getent.noded_uid,
|
196 |
getent.masterd_gid), |
197 |
(constants.DISK_LINKS_DIR, DIR, 0755, getent.noded_uid,
|
198 |
getent.masterd_gid), |
199 |
(constants.CRYPTO_KEYS_DIR, DIR, 0700, getent.noded_uid,
|
200 |
getent.masterd_gid), |
201 |
(constants.IMPORT_EXPORT_DIR, DIR, 0755, getent.noded_uid,
|
202 |
getent.masterd_gid), |
203 |
(constants.LOG_DIR, DIR, 0770, getent.masterd_uid,
|
204 |
getent.daemons_gid), |
205 |
(masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid,
|
206 |
False),
|
207 |
(confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False), |
208 |
(noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False), |
209 |
(rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False), |
210 |
(constants.LOG_OS_DIR, DIR, 0750, getent.masterd_uid,
|
211 |
getent.daemons_gid), |
212 |
]) |
213 |
|
214 |
return tuple(paths) |
215 |
|
216 |
|
217 |
def ParseOptions(): |
218 |
"""Parses the options passed to the program.
|
219 |
|
220 |
@return: Options and arguments
|
221 |
|
222 |
"""
|
223 |
program = os.path.basename(sys.argv[0])
|
224 |
|
225 |
parser = optparse.OptionParser(usage="%%prog [--full-run]",
|
226 |
prog=program) |
227 |
parser.add_option("--full-run", "-f", dest="full_run", action="store_true", |
228 |
default=False, help=("Make a full run and collect" |
229 |
" additional files (time consuming)"))
|
230 |
|
231 |
return parser.parse_args()
|
232 |
|
233 |
|
234 |
def Main(): |
235 |
"""Main routine.
|
236 |
|
237 |
"""
|
238 |
getent = runtime.GetEnts() |
239 |
(opts, _) = ParseOptions() |
240 |
|
241 |
try:
|
242 |
for path in GetPaths(): |
243 |
ProcessPath(path) |
244 |
|
245 |
if opts.full_run:
|
246 |
RecursiveEnsure(constants.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid, |
247 |
getent.masterd_gid, 0700, 0600) |
248 |
except EnsureError, err:
|
249 |
print >> sys.stderr, "An error occurred while ensure permissions:", err |
250 |
return constants.EXIT_FAILURE
|
251 |
|
252 |
return constants.EXIT_SUCCESS
|