Statistics
| Branch: | Tag: | Revision:

root / lib / runtime.py @ 670e954a

History | View | Annotate | Download (6.6 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 queryd_uid: The resolved uid of the queryd user
79
  @ivar queyrd_gid: The resolved gid of the queyrd group
80
  @ivar rapi_uid: The resolved uid of the rapi user
81
  @ivar rapi_gid: The resolved gid of the rapi group
82
  @ivar noded_uid: The resolved uid of the noded user
83
  @ivar daemons_gid: The resolved gid of the daemons group
84
  @ivar admin_gid: The resolved gid of the admin group
85

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

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

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

    
98
    self.queryd_uid = GetUid(constants.QUERYD_USER, _getpwnam)
99
    self.queryd_gid = GetGid(constants.QUERYD_GROUP, _getgrnam)
100

    
101
    self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam)
102
    self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam)
103

    
104
    self.noded_uid = GetUid(constants.NODED_USER, _getpwnam)
105
    self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam)
106

    
107
    # Misc Ganeti groups
108
    self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam)
109
    self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam)
110

    
111
    self._uid2user = {
112
      self.masterd_uid: constants.MASTERD_USER,
113
      self.confd_uid: constants.CONFD_USER,
114
      self.queryd_uid: constants.QUERYD_USER,
115
      self.rapi_uid: constants.RAPI_USER,
116
      self.noded_uid: constants.NODED_USER,
117
      }
118

    
119
    self._gid2group = {
120
      self.masterd_gid: constants.MASTERD_GROUP,
121
      self.confd_gid: constants.CONFD_GROUP,
122
      self.queryd_gid: constants.QUERYD_GROUP,
123
      self.rapi_gid: constants.RAPI_GROUP,
124
      self.noded_gid: constants.NODED_GROUP,
125
      self.daemons_gid: constants.DAEMONS_GROUP,
126
      self.admin_gid: constants.ADMIN_GROUP,
127
      }
128

    
129
    self._user2uid = utils.InvertDict(self._uid2user)
130
    self._group2gid = utils.InvertDict(self._gid2group)
131

    
132
  def LookupUid(self, uid):
133
    """Looks which Ganeti user belongs to this uid.
134

135
    @param uid: The uid to lookup
136
    @returns The user name associated with that uid
137

138
    """
139
    try:
140
      return self._uid2user[uid]
141
    except KeyError:
142
      raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
143

    
144
  def LookupGid(self, gid):
145
    """Looks which Ganeti group belongs to this gid.
146

147
    @param gid: The gid to lookup
148
    @returns The group name associated with that gid
149

150
    """
151
    try:
152
      return self._gid2group[gid]
153
    except KeyError:
154
      raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
155

    
156
  def LookupUser(self, name):
157
    """Looks which uid belongs to this name.
158

159
    @param name: The name to lookup
160
    @returns The uid associated with that user name
161

162
    """
163
    try:
164
      return self._user2uid[name]
165
    except KeyError:
166
      raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
167

    
168
  def LookupGroup(self, name):
169
    """Looks which gid belongs to this name.
170

171
    @param name: The name to lookup
172
    @returns The gid associated with that group name
173

174
    """
175
    try:
176
      return self._group2gid[name]
177
    except KeyError:
178
      raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
179

    
180

    
181
def GetEnts(resolver=GetentResolver):
182
  """Singleton wrapper around resolver instance.
183

184
  As this method is accessed by multiple threads at the same time
185
  we need to take thread-safety carefully.
186

187
  """
188
  # We need to use the global keyword here
189
  global _priv # pylint: disable=W0603
190

    
191
  if not _priv:
192
    _priv_lock.acquire()
193
    try:
194
      if not _priv:
195
        # W0621: Redefine '_priv' from outer scope (used for singleton)
196
        _priv = resolver() # pylint: disable=W0621
197
    finally:
198
      _priv_lock.release()
199

    
200
  return _priv
201

    
202

    
203
def InitArchInfo():
204
  """Initialize architecture information.
205

206
  We can assume this information never changes during the lifetime of a
207
  process, therefore the information can easily be cached.
208

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

214
  """
215
  global _arch # pylint: disable=W0603
216

    
217
  if _arch is not None:
218
    raise errors.ProgrammerError("Architecture information can only be"
219
                                 " initialized once")
220

    
221
  _arch = (platform.architecture()[0], platform.machine())
222

    
223

    
224
def GetArchInfo():
225
  """Returns previsouly initialized architecture information.
226

227
  """
228
  if _arch is None:
229
    raise errors.ProgrammerError("Architecture information hasn't been"
230
                                 " initialized")
231

    
232
  return _arch