LUClusterVerifyGroup: Spread SSH checks over more nodes
[ganeti-local] / lib / runtime.py
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
30 from ganeti import constants
31 from ganeti import errors
32 from ganeti import utils
33
34
35 _priv = None
36 _priv_lock = threading.Lock()
37
38
39 def GetUid(user, _getpwnam):
40   """Retrieve the uid from the database.
41
42   @type user: string
43   @param user: The username to retrieve
44   @return: The resolved uid
45
46   """
47   try:
48     return _getpwnam(user).pw_uid
49   except KeyError, err:
50     raise errors.ConfigurationError("User '%s' not found (%s)" % (user, err))
51
52
53 def GetGid(group, _getgrnam):
54   """Retrieve the gid from the database.
55
56   @type group: string
57   @param group: The group name to retrieve
58   @return: The resolved gid
59
60   """
61   try:
62     return _getgrnam(group).gr_gid
63   except KeyError, err:
64     raise errors.ConfigurationError("Group '%s' not found (%s)" % (group, err))
65
66
67 class GetentResolver:
68   """Resolves Ganeti uids and gids by name.
69
70   @ivar masterd_uid: The resolved uid of the masterd user
71   @ivar masterd_gid: The resolved gid of the masterd group
72   @ivar confd_uid: The resolved uid of the confd user
73   @ivar confd_gid: The resolved gid of the confd group
74   @ivar rapi_uid: The resolved uid of the rapi user
75   @ivar rapi_gid: The resolved gid of the rapi group
76   @ivar noded_uid: The resolved uid of the noded user
77
78   @ivar daemons_gid: The resolved gid of the daemons group
79   @ivar admin_gid: The resolved gid of the admin group
80   """
81   def __init__(self, _getpwnam=pwd.getpwnam, _getgrnam=grp.getgrnam):
82     """Initialize the resolver.
83
84     """
85     # Daemon pairs
86     self.masterd_uid = GetUid(constants.MASTERD_USER, _getpwnam)
87     self.masterd_gid = GetGid(constants.MASTERD_GROUP, _getgrnam)
88
89     self.confd_uid = GetUid(constants.CONFD_USER, _getpwnam)
90     self.confd_gid = GetGid(constants.CONFD_GROUP, _getgrnam)
91
92     self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam)
93     self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam)
94
95     self.noded_uid = GetUid(constants.NODED_USER, _getpwnam)
96     self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam)
97
98     # Misc Ganeti groups
99     self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam)
100     self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam)
101
102     self._uid2user = {
103       self.masterd_uid: constants.MASTERD_USER,
104       self.confd_uid: constants.CONFD_USER,
105       self.rapi_uid: constants.RAPI_USER,
106       self.noded_uid: constants.NODED_USER,
107       }
108
109     self._gid2group = {
110       self.masterd_gid: constants.MASTERD_GROUP,
111       self.confd_gid: constants.CONFD_GROUP,
112       self.rapi_gid: constants.RAPI_GROUP,
113       self.noded_gid: constants.NODED_GROUP,
114       self.daemons_gid: constants.DAEMONS_GROUP,
115       self.admin_gid: constants.ADMIN_GROUP,
116       }
117
118     self._user2uid = utils.InvertDict(self._uid2user)
119     self._group2gid = utils.InvertDict(self._gid2group)
120
121   def LookupUid(self, uid):
122     """Looks which Ganeti user belongs to this uid.
123
124     @param uid: The uid to lookup
125     @returns The user name associated with that uid
126
127     """
128     try:
129       return self._uid2user[uid]
130     except KeyError:
131       raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
132
133   def LookupGid(self, gid):
134     """Looks which Ganeti group belongs to this gid.
135
136     @param gid: The gid to lookup
137     @returns The group name associated with that gid
138
139     """
140     try:
141       return self._gid2group[gid]
142     except KeyError:
143       raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
144
145   def LookupUser(self, name):
146     """Looks which uid belongs to this name.
147
148     @param name: The name to lookup
149     @returns The uid associated with that user name
150
151     """
152     try:
153       return self._user2uid[name]
154     except KeyError:
155       raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
156
157   def LookupGroup(self, name):
158     """Looks which gid belongs to this name.
159
160     @param name: The name to lookup
161     @returns The gid associated with that group name
162
163     """
164     try:
165       return self._group2gid[name]
166     except KeyError:
167       raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
168
169
170 def GetEnts(resolver=GetentResolver):
171   """Singleton wrapper around resolver instance.
172
173   As this method is accessed by multiple threads at the same time
174   we need to take thread-safty carefully
175
176   """
177   # We need to use the global keyword here
178   global _priv # pylint: disable=W0603
179
180   if not _priv:
181     _priv_lock.acquire()
182     try:
183       if not _priv:
184         # W0621: Redefine '_priv' from outer scope (used for singleton)
185         _priv = resolver() # pylint: disable=W0621
186     finally:
187       _priv_lock.release()
188
189   return _priv