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