Statistics
| Branch: | Tag: | Revision:

root / lib / runtime.py @ 93f1e606

History | View | Annotate | Download (8 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 luxi
34
from ganeti.rpc.errors import NoMasterError
35
from ganeti import pathutils
36
from ganeti import ssconf
37
from ganeti import utils
38

    
39

    
40
_priv = None
41
_priv_lock = threading.Lock()
42

    
43
#: Architecture information
44
_arch = None
45

    
46

    
47
def GetUid(user, _getpwnam):
48
  """Retrieve the uid from the database.
49

50
  @type user: string
51
  @param user: The username to retrieve
52
  @return: The resolved uid
53

54
  """
55
  try:
56
    return _getpwnam(user).pw_uid
57
  except KeyError, err:
58
    raise errors.ConfigurationError("User '%s' not found (%s)" % (user, err))
59

    
60

    
61
def GetGid(group, _getgrnam):
62
  """Retrieve the gid from the database.
63

64
  @type group: string
65
  @param group: The group name to retrieve
66
  @return: The resolved gid
67

68
  """
69
  try:
70
    return _getgrnam(group).gr_gid
71
  except KeyError, err:
72
    raise errors.ConfigurationError("Group '%s' not found (%s)" % (group, err))
73

    
74

    
75
class GetentResolver:
76
  """Resolves Ganeti uids and gids by name.
77

78
  @ivar masterd_uid: The resolved uid of the masterd user
79
  @ivar masterd_gid: The resolved gid of the masterd group
80
  @ivar confd_uid: The resolved uid of the confd user
81
  @ivar confd_gid: The resolved gid of the confd group
82
  @ivar wconfd_uid: The resolved uid of the wconfd user
83
  @ivar wconfd_gid: The resolved gid of the wconfd group
84
  @ivar luxid_uid: The resolved uid of the luxid user
85
  @ivar luxid_gid: The resolved gid of the luxid group
86
  @ivar rapi_uid: The resolved uid of the rapi user
87
  @ivar rapi_gid: The resolved gid of the rapi group
88
  @ivar noded_uid: The resolved uid of the noded user
89
  @ivar daemons_gid: The resolved gid of the daemons group
90
  @ivar admin_gid: The resolved gid of the admin group
91

92
  """
93
  def __init__(self, _getpwnam=pwd.getpwnam, _getgrnam=grp.getgrnam):
94
    """Initialize the resolver.
95

96
    """
97
    # Daemon pairs
98
    self.masterd_uid = GetUid(constants.MASTERD_USER, _getpwnam)
99
    self.masterd_gid = GetGid(constants.MASTERD_GROUP, _getgrnam)
100

    
101
    self.confd_uid = GetUid(constants.CONFD_USER, _getpwnam)
102
    self.confd_gid = GetGid(constants.CONFD_GROUP, _getgrnam)
103

    
104
    self.wconfd_uid = GetUid(constants.WCONFD_USER, _getpwnam)
105
    self.wconfd_gid = GetGid(constants.WCONFD_GROUP, _getgrnam)
106

    
107
    self.luxid_uid = GetUid(constants.LUXID_USER, _getpwnam)
108
    self.luxid_gid = GetGid(constants.LUXID_GROUP, _getgrnam)
109

    
110
    self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam)
111
    self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam)
112

    
113
    self.noded_uid = GetUid(constants.NODED_USER, _getpwnam)
114
    self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam)
115

    
116
    self.mond_uid = GetUid(constants.MOND_USER, _getpwnam)
117
    self.mond_gid = GetGid(constants.MOND_GROUP, _getgrnam)
118

    
119
    # Misc Ganeti groups
120
    self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam)
121
    self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam)
122

    
123
    self._uid2user = {
124
      self.masterd_uid: constants.MASTERD_USER,
125
      self.confd_uid: constants.CONFD_USER,
126
      self.wconfd_uid: constants.WCONFD_USER,
127
      self.luxid_uid: constants.LUXID_USER,
128
      self.rapi_uid: constants.RAPI_USER,
129
      self.noded_uid: constants.NODED_USER,
130
      self.mond_uid: constants.MOND_USER,
131
      }
132

    
133
    self._gid2group = {
134
      self.masterd_gid: constants.MASTERD_GROUP,
135
      self.confd_gid: constants.CONFD_GROUP,
136
      self.wconfd_gid: constants.WCONFD_GROUP,
137
      self.luxid_gid: constants.LUXID_GROUP,
138
      self.rapi_gid: constants.RAPI_GROUP,
139
      self.noded_gid: constants.NODED_GROUP,
140
      self.mond_gid: constants.MOND_GROUP,
141
      self.daemons_gid: constants.DAEMONS_GROUP,
142
      self.admin_gid: constants.ADMIN_GROUP,
143
      }
144

    
145
    self._user2uid = utils.InvertDict(self._uid2user)
146
    self._group2gid = utils.InvertDict(self._gid2group)
147

    
148
  def LookupUid(self, uid):
149
    """Looks which Ganeti user belongs to this uid.
150

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

154
    """
155
    try:
156
      return self._uid2user[uid]
157
    except KeyError:
158
      raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
159

    
160
  def LookupGid(self, gid):
161
    """Looks which Ganeti group belongs to this gid.
162

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

166
    """
167
    try:
168
      return self._gid2group[gid]
169
    except KeyError:
170
      raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
171

    
172
  def LookupUser(self, name):
173
    """Looks which uid belongs to this name.
174

175
    @param name: The name to lookup
176
    @returns The uid associated with that user name
177

178
    """
179
    try:
180
      return self._user2uid[name]
181
    except KeyError:
182
      raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
183

    
184
  def LookupGroup(self, name):
185
    """Looks which gid belongs to this name.
186

187
    @param name: The name to lookup
188
    @returns The gid associated with that group name
189

190
    """
191
    try:
192
      return self._group2gid[name]
193
    except KeyError:
194
      raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
195

    
196

    
197
def GetEnts(resolver=GetentResolver):
198
  """Singleton wrapper around resolver instance.
199

200
  As this method is accessed by multiple threads at the same time
201
  we need to take thread-safety carefully.
202

203
  """
204
  # We need to use the global keyword here
205
  global _priv # pylint: disable=W0603
206

    
207
  if not _priv:
208
    _priv_lock.acquire()
209
    try:
210
      if not _priv:
211
        # W0621: Redefine '_priv' from outer scope (used for singleton)
212
        _priv = resolver() # pylint: disable=W0621
213
    finally:
214
      _priv_lock.release()
215

    
216
  return _priv
217

    
218

    
219
def InitArchInfo():
220
  """Initialize architecture information.
221

222
  We can assume this information never changes during the lifetime of a
223
  process, therefore the information can easily be cached.
224

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

230
  """
231
  global _arch # pylint: disable=W0603
232

    
233
  if _arch is not None:
234
    raise errors.ProgrammerError("Architecture information can only be"
235
                                 " initialized once")
236

    
237
  _arch = (platform.architecture()[0], platform.machine())
238

    
239

    
240
def GetArchInfo():
241
  """Returns previsouly initialized architecture information.
242

243
  """
244
  if _arch is None:
245
    raise errors.ProgrammerError("Architecture information hasn't been"
246
                                 " initialized")
247

    
248
  return _arch
249

    
250

    
251
def GetClient():
252
  """Connects to the a luxi socket and returns a client.
253

254
  """
255
  try:
256
    client = luxi.Client(address=pathutils.QUERY_SOCKET)
257
  except NoMasterError:
258
    ss = ssconf.SimpleStore()
259

    
260
    # Try to read ssconf file
261
    try:
262
      ss.GetMasterNode()
263
    except errors.ConfigurationError:
264
      raise errors.OpPrereqError("Cluster not initialized or this machine is"
265
                                 " not part of a cluster",
266
                                 errors.ECODE_INVAL)
267

    
268
    master, myself = ssconf.GetMasterAndMyself(ss=ss)
269
    if master != myself:
270
      raise errors.OpPrereqError("This is not the master node, please connect"
271
                                 " to node '%s' and rerun the command" %
272
                                 master, errors.ECODE_INVAL)
273
    raise
274
  return client