Statistics
| Branch: | Tag: | Revision:

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