Fix owner of the OS log dir
[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   rapi_log = constants.DAEMONS_LOGFILES[constants.RAPI]
126
127   rapi_dir = os.path.join(pathutils.DATA_DIR, "rapi")
128   cleaner_log_dir = os.path.join(pathutils.LOG_DIR, "cleaner")
129   master_cleaner_log_dir = os.path.join(pathutils.LOG_DIR, "master-cleaner")
130
131   # A note on the ordering: The parent directory (type C{DIR}) must always be
132   # listed before files (type C{FILE}) in that directory. Once the directory is
133   # set, only files directly in that directory can be listed.
134   paths = [
135     (pathutils.DATA_DIR, DIR, 0755, getent.masterd_uid, getent.masterd_gid),
136     (pathutils.CLUSTER_DOMAIN_SECRET_FILE, FILE, 0640,
137      getent.masterd_uid, getent.masterd_gid, False),
138     (pathutils.CLUSTER_CONF_FILE, FILE, 0640,
139      getent.masterd_uid, getent.confd_gid, False),
140     (pathutils.CONFD_HMAC_KEY, FILE, 0440,
141      getent.confd_uid, getent.masterd_gid, False),
142     (pathutils.SSH_KNOWN_HOSTS_FILE, FILE, 0644,
143      getent.masterd_uid, getent.masterd_gid, False),
144     (pathutils.RAPI_CERT_FILE, FILE, 0440,
145      getent.rapi_uid, getent.masterd_gid, False),
146     (pathutils.SPICE_CERT_FILE, FILE, 0440,
147      getent.noded_uid, getent.masterd_gid, False),
148     (pathutils.SPICE_CACERT_FILE, FILE, 0440,
149      getent.noded_uid, getent.masterd_gid, False),
150     (pathutils.NODED_CERT_FILE, FILE, pathutils.NODED_CERT_MODE,
151      getent.masterd_uid, getent.masterd_gid, False),
152     (pathutils.WATCHER_PAUSEFILE, FILE, 0644,
153      getent.masterd_uid, getent.masterd_gid, False),
154     ]
155
156   ss = ssconf.SimpleStore()
157   for ss_path in ss.GetFileList():
158     paths.append((ss_path, FILE, constants.SS_FILE_PERMS,
159                   getent.noded_uid, getent.noded_gid, False))
160
161   paths.extend([
162     (pathutils.QUEUE_DIR, DIR, 0750, getent.masterd_uid, getent.daemons_gid),
163     (pathutils.QUEUE_DIR, QUEUE_DIR, constants.JOB_QUEUE_FILES_PERMS,
164      getent.masterd_uid, getent.daemons_gid),
165     (pathutils.JOB_QUEUE_DRAIN_FILE, FILE, 0644,
166      getent.masterd_uid, getent.daemons_gid, False),
167     (pathutils.JOB_QUEUE_LOCK_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
168      getent.masterd_uid, getent.daemons_gid, False),
169     (pathutils.JOB_QUEUE_SERIAL_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
170      getent.masterd_uid, getent.daemons_gid, False),
171     (pathutils.JOB_QUEUE_VERSION_FILE, FILE, constants.JOB_QUEUE_FILES_PERMS,
172      getent.masterd_uid, getent.daemons_gid, False),
173     (pathutils.JOB_QUEUE_ARCHIVE_DIR, DIR, 0740,
174      getent.masterd_uid, getent.daemons_gid),
175     (rapi_dir, DIR, 0750, getent.rapi_uid, getent.masterd_gid),
176     (pathutils.RAPI_USERS_FILE, FILE, 0640,
177      getent.rapi_uid, getent.masterd_gid, False),
178     (pathutils.RUN_DIR, DIR, 0775, getent.masterd_uid, getent.daemons_gid),
179     (pathutils.SOCKET_DIR, DIR, 0770, getent.masterd_uid, getent.daemons_gid),
180     (pathutils.MASTER_SOCKET, FILE, 0660,
181      getent.masterd_uid, getent.daemons_gid, False),
182     (pathutils.BDEV_CACHE_DIR, DIR, 0755,
183      getent.noded_uid, getent.masterd_gid),
184     (pathutils.UIDPOOL_LOCKDIR, DIR, 0750,
185      getent.noded_uid, getent.masterd_gid),
186     (pathutils.DISK_LINKS_DIR, DIR, 0755,
187      getent.noded_uid, getent.masterd_gid),
188     (pathutils.CRYPTO_KEYS_DIR, DIR, 0700,
189      getent.noded_uid, getent.masterd_gid),
190     (pathutils.IMPORT_EXPORT_DIR, DIR, 0755,
191      getent.noded_uid, getent.masterd_gid),
192     (pathutils.LOG_DIR, DIR, 0770, getent.masterd_uid, getent.daemons_gid),
193     (masterd_log, FILE, 0600, getent.masterd_uid, getent.masterd_gid, False),
194     (confd_log, FILE, 0600, getent.confd_uid, getent.masterd_gid, False),
195     (noded_log, FILE, 0600, getent.noded_uid, getent.masterd_gid, False),
196     (rapi_log, FILE, 0600, getent.rapi_uid, getent.masterd_gid, False),
197     (pathutils.LOG_OS_DIR, DIR, 0750, getent.noded_uid, getent.daemons_gid),
198     (cleaner_log_dir, DIR, 0750, getent.noded_uid, getent.noded_gid),
199     (master_cleaner_log_dir, DIR, 0750, getent.masterd_uid, getent.masterd_gid),
200     ])
201
202   return paths
203
204
205 def ParseOptions():
206   """Parses the options passed to the program.
207
208   @return: Options and arguments
209
210   """
211   program = os.path.basename(sys.argv[0])
212
213   parser = optparse.OptionParser(usage="%prog [--full-run]",
214                                  prog=program)
215   parser.add_option(cli.DEBUG_OPT)
216   parser.add_option(cli.VERBOSE_OPT)
217   parser.add_option("--full-run", "-f", dest="full_run", action="store_true",
218                     default=False, help=("Make a full run and set permissions"
219                                          " on archived jobs (time consuming)"))
220
221   return parser.parse_args()
222
223
224 def Main():
225   """Main routine.
226
227   """
228   (opts, args) = ParseOptions()
229
230   utils.SetupToolLogging(opts.debug, opts.verbose)
231
232   if args:
233     logging.error("No arguments are expected")
234     return constants.EXIT_FAILURE
235
236   if opts.full_run:
237     logging.info("Running in full mode")
238
239   getent = runtime.GetEnts()
240
241   try:
242     for path in GetPaths():
243       ProcessPath(path)
244
245     if opts.full_run:
246       RecursiveEnsure(pathutils.JOB_QUEUE_ARCHIVE_DIR, getent.masterd_uid,
247                       getent.daemons_gid, 0750, constants.JOB_QUEUE_FILES_PERMS)
248   except errors.GenericError, err:
249     logging.error("An error occurred while setting permissions: %s", err)
250     return constants.EXIT_FAILURE
251
252   return constants.EXIT_SUCCESS