Statistics
| Branch: | Tag: | Revision:

root / lib / runtime.py @ 91c17910

History | View | Annotate | Download (6.3 kB)

1
#
2
#
3

    
4
# Copyright (C) 2010 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
"""Module implementing configuration details at runtime.
22

23
"""
24

    
25

    
26
import grp
27
import pwd
28
import threading
29
import platform
30

    
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti import utils
34

    
35

    
36
_priv = None
37
_priv_lock = threading.Lock()
38

    
39
#: Architecture information
40
_arch = None
41

    
42

    
43
def GetUid(user, _getpwnam):
44
  """Retrieve the uid from the database.
45

46
  @type user: string
47
  @param user: The username to retrieve
48
  @return: The resolved uid
49

50
  """
51
  try:
52
    return _getpwnam(user).pw_uid
53
  except KeyError, err:
54
    raise errors.ConfigurationError("User '%s' not found (%s)" % (user, err))
55

    
56

    
57
def GetGid(group, _getgrnam):
58
  """Retrieve the gid from the database.
59

60
  @type group: string
61
  @param group: The group name to retrieve
62
  @return: The resolved gid
63

64
  """
65
  try:
66
    return _getgrnam(group).gr_gid
67
  except KeyError, err:
68
    raise errors.ConfigurationError("Group '%s' not found (%s)" % (group, err))
69

    
70

    
71
class GetentResolver:
72
  """Resolves Ganeti uids and gids by name.
73

74
  @ivar masterd_uid: The resolved uid of the masterd user
75
  @ivar masterd_gid: The resolved gid of the masterd group
76
  @ivar confd_uid: The resolved uid of the confd user
77
  @ivar confd_gid: The resolved gid of the confd group
78
  @ivar rapi_uid: The resolved uid of the rapi user
79
  @ivar rapi_gid: The resolved gid of the rapi group
80
  @ivar noded_uid: The resolved uid of the noded user
81
  @ivar daemons_gid: The resolved gid of the daemons group
82
  @ivar admin_gid: The resolved gid of the admin group
83

84
  """
85
  def __init__(self, _getpwnam=pwd.getpwnam, _getgrnam=grp.getgrnam):
86
    """Initialize the resolver.
87

88
    """
89
    # Daemon pairs
90
    self.masterd_uid = GetUid(constants.MASTERD_USER, _getpwnam)
91
    self.masterd_gid = GetGid(constants.MASTERD_GROUP, _getgrnam)
92

    
93
    self.confd_uid = GetUid(constants.CONFD_USER, _getpwnam)
94
    self.confd_gid = GetGid(constants.CONFD_GROUP, _getgrnam)
95

    
96
    self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam)
97
    self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam)
98

    
99
    self.noded_uid = GetUid(constants.NODED_USER, _getpwnam)
100
    self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam)
101

    
102
    # Misc Ganeti groups
103
    self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam)
104
    self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam)
105

    
106
    self._uid2user = {
107
      self.masterd_uid: constants.MASTERD_USER,
108
      self.confd_uid: constants.CONFD_USER,
109
      self.rapi_uid: constants.RAPI_USER,
110
      self.noded_uid: constants.NODED_USER,
111
      }
112

    
113
    self._gid2group = {
114
      self.masterd_gid: constants.MASTERD_GROUP,
115
      self.confd_gid: constants.CONFD_GROUP,
116
      self.rapi_gid: constants.RAPI_GROUP,
117
      self.noded_gid: constants.NODED_GROUP,
118
      self.daemons_gid: constants.DAEMONS_GROUP,
119
      self.admin_gid: constants.ADMIN_GROUP,
120
      }
121

    
122
    self._user2uid = utils.InvertDict(self._uid2user)
123
    self._group2gid = utils.InvertDict(self._gid2group)
124

    
125
  def LookupUid(self, uid):
126
    """Looks which Ganeti user belongs to this uid.
127

128
    @param uid: The uid to lookup
129
    @returns The user name associated with that uid
130

131
    """
132
    try:
133
      return self._uid2user[uid]
134
    except KeyError:
135
      raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
136

    
137
  def LookupGid(self, gid):
138
    """Looks which Ganeti group belongs to this gid.
139

140
    @param gid: The gid to lookup
141
    @returns The group name associated with that gid
142

143
    """
144
    try:
145
      return self._gid2group[gid]
146
    except KeyError:
147
      raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
148

    
149
  def LookupUser(self, name):
150
    """Looks which uid belongs to this name.
151

152
    @param name: The name to lookup
153
    @returns The uid associated with that user name
154

155
    """
156
    try:
157
      return self._user2uid[name]
158
    except KeyError:
159
      raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
160

    
161
  def LookupGroup(self, name):
162
    """Looks which gid belongs to this name.
163

164
    @param name: The name to lookup
165
    @returns The gid associated with that group name
166

167
    """
168
    try:
169
      return self._group2gid[name]
170
    except KeyError:
171
      raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
172

    
173

    
174
def GetEnts(resolver=GetentResolver):
175
  """Singleton wrapper around resolver instance.
176

177
  As this method is accessed by multiple threads at the same time
178
  we need to take thread-safety carefully.
179

180
  """
181
  # We need to use the global keyword here
182
  global _priv # pylint: disable=W0603
183

    
184
  if not _priv:
185
    _priv_lock.acquire()
186
    try:
187
      if not _priv:
188
        # W0621: Redefine '_priv' from outer scope (used for singleton)
189
        _priv = resolver() # pylint: disable=W0621
190
    finally:
191
      _priv_lock.release()
192

    
193
  return _priv
194

    
195

    
196
def InitArchInfo():
197
  """Initialize architecture information.
198

199
  We can assume this information never changes during the lifetime of a
200
  process, therefore the information can easily be cached.
201

202
  @note: This function uses C{platform.architecture} to retrieve the Python
203
    binary architecture and does so by forking to run C{file} (see Python
204
    documentation for more information). Therefore it must not be used in a
205
    multi-threaded environment.
206

207
  """
208
  global _arch # pylint: disable=W0603
209

    
210
  if _arch is not None:
211
    raise errors.ProgrammerError("Architecture information can only be"
212
                                 " initialized once")
213

    
214
  _arch = (platform.architecture()[0], platform.machine())
215

    
216

    
217
def GetArchInfo():
218
  """Returns previsouly initialized architecture information.
219

220
  """
221
  if _arch is None:
222
    raise errors.ProgrammerError("Architecture information hasn't been"
223
                                 " initialized")
224

    
225
  return _arch