Fix permission errors for split users
[ganeti-local] / lib / tools / ensure_dirs.py
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 os
26 import os.path
27 import optparse
28 import sys
29 import logging
30
31 from ganeti import constants
32 from ganeti import errors
33 from ganeti import runtime
34 from ganeti import ssconf
35 from ganeti import utils
36 from ganeti import cli
37 from ganeti import pathutils
38 from ganeti import compat
39
40
41 (DIR,
42  FILE,
43  QUEUE_DIR) = range(1, 4)
44
45 ALL_TYPES = compat.UniqueFrozenset([
46   DIR,
47   FILE,
48   QUEUE_DIR,
49   ])
50
51
52 def RecursiveEnsure(path, uid, gid, dir_perm, file_perm):
53   """Ensures permissions recursively down a directory.
54
55   This functions walks the path and sets permissions accordingly.
56
57   @param path: The absolute path to walk
58   @param uid: The uid used as owner
59   @param gid: The gid used as group
60   @param dir_perm: The permission bits set for directories
61   @param file_perm: The permission bits set for files
62
63   """
64   assert os.path.isabs(path), "Path %s is not absolute" % path
65   assert os.path.isdir(path), "Path %s is not a dir" % path
66
67   logging.debug("Recursively processing %s", path)
68
69   for root, dirs, files in os.walk(path):
70     for subdir in dirs:
71       utils.EnforcePermission(os.path.join(root, subdir), dir_perm, uid=uid,
72                               gid=gid)
73
74     for filename in files:
75       utils.EnforcePermission(os.path.join(root, filename), file_perm, uid=uid,
76                               gid=gid)
77
78
79 def EnsureQueueDir(path, mode, uid, gid):
80   """Sets the correct permissions on all job files in the queue.
81
82   @param path: Directory path
83   @param mode: Wanted file mode
84   @param uid: Wanted user ID
85   @param gid: Wanted group ID
86
87   """
88   for filename in utils.ListVisibleFiles(path):
89     if constants.JOB_FILE_RE.match(filename):
90       utils.EnforcePermission(utils.PathJoin(path, filename), mode, uid=uid,
91                               gid=gid)
92
93
94 def ProcessPath(path):
95   """Processes a path component.
96
97   @param path: A tuple of the path component to process
98
99   """
100   (pathname, pathtype, mode, uid, gid) = path[0:5]
101
102   assert pathtype in ALL_TYPES
103
104   if pathtype in (DIR, QUEUE_DIR):
105     # No additional parameters
106     assert len(path) == 5
107     if pathtype == DIR:
108       utils.MakeDirWithPerm(pathname, mode, uid, gid)
109     elif pathtype == QUEUE_DIR:
110       EnsureQueueDir(pathname, mode, uid, gid)
111   elif pathtype == FILE:
112     (must_exist, ) = path[5:]
113     utils.EnforcePermission(pathname, mode, uid=uid, gid=gid,
114                             must_exist=must_exist)
115
116
117 def GetPaths():
118   """Returns a tuple of path objects to process.
119
120   """
121   getent = runtime.GetEnts()
122   masterd_log = constants.DAEMONS_LOGFILES[constants.MASTERD]
123   noded_log = constants.DAEMONS_LOGFILES[constants.NODED]
124   confd_log = constants.DAEMONS_LOGFILES[constants.CONFD]
125   luxid_log = constants.DAEMONS_LOGFILES[constants.LUXID]
126   rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI]
127   mond_log = constants.DAEMONS_LOGFILES[constants.MOND]
128
129   rapi_dir = os.path.join(pathutils.DATA_DIR, "rapi")
130   cleaner_log_dir = os.path.join(pathutils.LOG_DIR, "cleaner")
131   master_cleaner_log_dir = os.path.join(pathutils.LOG_DIR, "master-cleaner")
132
133   # A note on the ordering: The parent directory (type C{DIR}) must always be
134   # listed before files (type C{FILE}) in that directory. Once the directory is
135   # set, only files directly in that directory can be listed.
136   paths = [
137     (pathutils.DATA_DIR, DIR, 0755, getent.masterd_uid, getent.masterd_gid),
138     (pathutils.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640,
139      getent.masterd_uid, getent.masterd_gid, False),
140     (pathutils.CLUSTER_CONF_FILE, FILE, 0640,
141      getent.masterd_uid, getent.confd_gid, False),
142     (pathutils.CONFD_HMAC_KEY, FILE, 0440,
143      getent.confd_uid, getent.masterd_gid, False),
144     (pathutils.SSH_KNOWN_HOSTS_FILE, FILE, 0644,
145      getent.masterd_uid, getent.masterd_gid, False),
146     (pathutils.RAPI_CERT_FILE, FILE, 0440,
147      getent.rapi_uid, getent.masterd_gid, False),
148     (pathutils.SPICE_CERT_FILE, FILE, 0440,
149      getent.noded_uid, getent.masterd_gid, False),
150     (pathutils.SPICE_CACERT_FILE, FILE, 0440,
151      getent.noded_uid, getent.masterd_gid, False),
152     (pathutils.NODED_CERT_FILE, FILE, pathutils.NODED_CERT_MODE,
153      getent.masterd_uid, getent.masterd_gid, False),
154     (pathutils.WATCHER_PAUSEFILE, FILE, 0644,
155      getent.masterd_uid, getent.masterd_gid, False),
156     ]
157
158   ss = ssconf.SimpleStore()
159   for ss_path in ss.GetFileList():
160     paths.append((ss_path, FILE, constants.SS_FILE_PERMS,
161                   getent.noded_uid, getent.noded_gid, False))
162
163   paths.extend([
164     (pathutils.QUEUE_DIR, DIR, 0750, getent.masterd_uid, getent.daemons_gid),
165     (pathutils.QUEUE_DIR, QUEUE_DIR, constants.JOB_QUEUE_FILES_PERMS,
166      getent.masterd_uid, getent.daemons_gid),
167     (pathutils.JOB_QUEUE_DRAIN_FILE, FILE, 0644,
168      getent.masterd_uid, getent.daemons_gid, False),
169     (pathutils.JOB_QUEUE_LOCK_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
170      getent.masterd_uid, getent.daemons_gid, False),
171     (pathutils.JOB_QUEUE_SERIAL_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
172      getent.masterd_uid, getent.daemons_gid, False),
173     (pathutils.JOB_QUEUE_VERSION_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
174      getent.masterd_uid, getent.daemons_gid, False),
175     (pathutils.JOB_QUEUE_ARCHIVE_DIR, DIR, 0750,
176      getent.masterd_uid, getent.daemons_gid),
177     (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
178     (pathutils.RAPI_USERS_FILE, FILE, 0640,
179      getent.rapi_uid, getent.masterd_gid, False),
180     (pathutils.RUN_DIR, DIR, 0775, getent.masterd_uid, getent.daemons_gid),
181     (pathutils.SOCKET_DIR, DIR, 0770, getent.masterd_uid, getent.daemons_gid),
182     (pathutils.MASTER_SOCKET, FILE, 0660,
183      getent.masterd_uid, getent.daemons_gid, False),
184     (pathutils.QUERY_SOCKET, FILE, 0660,
185      getent.luxid_uid, getent.daemons_gid, False),
186     (pathutils.BDEV_CACHE_DIR, DIR, 0755,
187      getent.noded_uid, getent.masterd_gid),
188     (pathutils.UIDPOOL_LOCKDIR, DIR, 0750,
189      getent.noded_uid, getent.masterd_gid),
190     (pathutils.DISK_LINKS_DIR, DIR, 0755,
191      getent.noded_uid, getent.masterd_gid),
192     (pathutils.CRYPTO_KEYS_DIR, DIR, 0700,
193      getent.noded_uid, getent.masterd_gid),
194     (pathutils.IMPORT_EXPORT_DIR, DIR, 0755,
195      getent.noded_uid, getent.masterd_gid),
196     (pathutils.LOG_DIR, DIR, 0770, getent.masterd_uid, getent.daemons_gid),
197     (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid, False),
198     (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False),
199     (luxid_log, FILE, 0600, getent.luxid_uid, getent.masterd_gid, False),
200     (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False),
201     (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False),
202     (mond_log, FILE, 0600, getent.mond_uid, getent.masterd_gid, False),
203     (pathutils.LOG_OS_DIR, DIR, 0750, getent.noded_uid, getent.daemons_gid),
204     (pathutils.LOG_XEN_DIR, DIR, 0750, getent.noded_uid, getent.daemons_gid),
205     (cleaner_log_dir, DIR, 0750, getent.noded_uid, getent.noded_gid),
206     (master_cleaner_log_dir, DIR, 0750, getent.masterd_uid, getent.masterd_gid),
207     (pathutils.INSTANCE_REASON_DIR, DIR, 0755, getent.noded_uid,
208      getent.noded_gid),
209     ])
210
211   return paths
212
213
214 def ParseOptions():
215   """Parses the options passed to the program.
216
217   @return: Options and arguments
218
219   """
220   program = os.path.basename(sys.argv[0])
221
222   parser = optparse.OptionParser(usage="%prog [--full-run]",
223                                  prog=program)
224   parser.add_option(cli.DEBUG_OPT)
225   parser.add_option(cli.VERBOSE_OPT)
226   parser.add_option("--full-run", "-f", dest="full_run", action="store_true",
227                     default=False, help=("Make a full run and set permissions"
228                                          " on archived jobs (time consuming)"))
229
230   return parser.parse_args()
231
232
233 def Main():
234   """Main routine.
235
236   """
237   (opts, args) = ParseOptions()
238
239   utils.SetupToolLogging(opts.debug, opts.verbose)
240
241   if args:
242     logging.error("No arguments are expected")
243     return constants.EXIT_FAILURE
244
245   if opts.full_run:
246     logging.info("Running in full mode")
247
248   getent = runtime.GetEnts()
249
250   try:
251     for path in GetPaths():
252       ProcessPath(path)
253
254     if opts.full_run:
255       RecursiveEnsure(pathutils.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid,
256                       getent.daemons_gid, 0750, constants.JOB_QUEUE_FILES_PERMS)
257   except errors.GenericError, err:
258     logging.error("An error occurred while setting permissions: %s", err)
259     return constants.EXIT_FAILURE
260
261   return constants.EXIT_SUCCESS