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