Package ganeti :: Module runtime
[hide private]
[frames] | no frames]

Source Code for Module ganeti.runtime

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2010 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30  """Module implementing configuration details at runtime. 
 31   
 32  """ 
 33   
 34   
 35  import grp 
 36  import pwd 
 37  import threading 
 38  import os 
 39  import platform 
 40   
 41  from ganeti import constants 
 42  from ganeti import errors 
 43  from ganeti import luxi 
 44  from ganeti.rpc.errors import NoMasterError 
 45  from ganeti import pathutils 
 46  from ganeti import ssconf 
 47  from ganeti import utils 
 48   
 49   
 50  _priv = None 
 51  _priv_lock = threading.Lock() 
 52   
 53  #: Architecture information 
 54  _arch = None 
 55   
 56   
57 -def GetUid(user, _getpwnam):
58 """Retrieve the uid from the database. 59 60 @type user: string 61 @param user: The username to retrieve 62 @return: The resolved uid 63 64 """ 65 try: 66 return _getpwnam(user).pw_uid 67 except KeyError, err: 68 raise errors.ConfigurationError("User '%s' not found (%s)" % (user, err))
69 70
71 -def GetGid(group, _getgrnam):
72 """Retrieve the gid from the database. 73 74 @type group: string 75 @param group: The group name to retrieve 76 @return: The resolved gid 77 78 """ 79 try: 80 return _getgrnam(group).gr_gid 81 except KeyError, err: 82 raise errors.ConfigurationError("Group '%s' not found (%s)" % (group, err))
83 84
85 -class GetentResolver(object):
86 """Resolves Ganeti uids and gids by name. 87 88 @ivar masterd_uid: The resolved uid of the masterd user 89 @ivar masterd_gid: The resolved gid of the masterd group 90 @ivar confd_uid: The resolved uid of the confd user 91 @ivar confd_gid: The resolved gid of the confd group 92 @ivar luxid_uid: The resolved uid of the luxid user 93 @ivar luxid_gid: The resolved gid of the luxid group 94 @ivar rapi_uid: The resolved uid of the rapi user 95 @ivar rapi_gid: The resolved gid of the rapi group 96 @ivar noded_uid: The resolved uid of the noded user 97 @ivar daemons_gid: The resolved gid of the daemons group 98 @ivar admin_gid: The resolved gid of the admin group 99 100 """
101 - def __init__(self, _getpwnam=pwd.getpwnam, _getgrnam=grp.getgrnam):
102 """Initialize the resolver. 103 104 """ 105 # Daemon pairs 106 self.masterd_uid = GetUid(constants.MASTERD_USER, _getpwnam) 107 self.masterd_gid = GetGid(constants.MASTERD_GROUP, _getgrnam) 108 109 self.confd_uid = GetUid(constants.CONFD_USER, _getpwnam) 110 self.confd_gid = GetGid(constants.CONFD_GROUP, _getgrnam) 111 112 self.luxid_uid = GetUid(constants.LUXID_USER, _getpwnam) 113 self.luxid_gid = GetGid(constants.LUXID_GROUP, _getgrnam) 114 115 self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam) 116 self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam) 117 118 self.noded_uid = GetUid(constants.NODED_USER, _getpwnam) 119 self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam) 120 121 self.mond_uid = GetUid(constants.MOND_USER, _getpwnam) 122 self.mond_gid = GetGid(constants.MOND_GROUP, _getgrnam) 123 124 # Misc Ganeti groups 125 self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam) 126 self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam) 127 128 self._uid2user = { 129 self.masterd_uid: constants.MASTERD_USER, 130 self.confd_uid: constants.CONFD_USER, 131 self.luxid_uid: constants.LUXID_USER, 132 self.rapi_uid: constants.RAPI_USER, 133 self.noded_uid: constants.NODED_USER, 134 self.mond_uid: constants.MOND_USER, 135 } 136 137 self._gid2group = { 138 self.masterd_gid: constants.MASTERD_GROUP, 139 self.confd_gid: constants.CONFD_GROUP, 140 self.luxid_gid: constants.LUXID_GROUP, 141 self.rapi_gid: constants.RAPI_GROUP, 142 self.noded_gid: constants.NODED_GROUP, 143 self.mond_gid: constants.MOND_GROUP, 144 self.daemons_gid: constants.DAEMONS_GROUP, 145 self.admin_gid: constants.ADMIN_GROUP, 146 } 147 148 self._user2uid = utils.InvertDict(self._uid2user) 149 self._group2gid = utils.InvertDict(self._gid2group)
150
151 - def LookupUid(self, uid):
152 """Looks which Ganeti user belongs to this uid. 153 154 @param uid: The uid to lookup 155 @returns The user name associated with that uid 156 157 """ 158 try: 159 return self._uid2user[uid] 160 except KeyError: 161 raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
162
163 - def LookupGid(self, gid):
164 """Looks which Ganeti group belongs to this gid. 165 166 @param gid: The gid to lookup 167 @returns The group name associated with that gid 168 169 """ 170 try: 171 return self._gid2group[gid] 172 except KeyError: 173 raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
174
175 - def LookupUser(self, name):
176 """Looks which uid belongs to this name. 177 178 @param name: The name to lookup 179 @returns The uid associated with that user name 180 181 """ 182 try: 183 return self._user2uid[name] 184 except KeyError: 185 raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
186
187 - def LookupGroup(self, name):
188 """Looks which gid belongs to this name. 189 190 @param name: The name to lookup 191 @returns The gid associated with that group name 192 193 """ 194 try: 195 return self._group2gid[name] 196 except KeyError: 197 raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
198 199
200 -def GetEnts(resolver=GetentResolver):
201 """Singleton wrapper around resolver instance. 202 203 As this method is accessed by multiple threads at the same time 204 we need to take thread-safety carefully. 205 206 """ 207 # We need to use the global keyword here 208 global _priv # pylint: disable=W0603 209 210 if not _priv: 211 _priv_lock.acquire() 212 try: 213 if not _priv: 214 # W0621: Redefine '_priv' from outer scope (used for singleton) 215 _priv = resolver() # pylint: disable=W0621 216 finally: 217 _priv_lock.release() 218 219 return _priv
220 221
222 -def InitArchInfo():
223 """Initialize architecture information. 224 225 We can assume this information never changes during the lifetime of a 226 process, therefore the information can easily be cached. 227 228 @note: This function uses C{platform.architecture} to retrieve the Python 229 binary architecture and does so by forking to run C{file} (see Python 230 documentation for more information). Therefore it must not be used in a 231 multi-threaded environment. 232 233 """ 234 global _arch # pylint: disable=W0603 235 236 if _arch is not None: 237 raise errors.ProgrammerError("Architecture information can only be" 238 " initialized once") 239 240 _arch = (platform.architecture()[0], platform.machine())
241 242
243 -def GetArchInfo():
244 """Returns previsouly initialized architecture information. 245 246 """ 247 if _arch is None: 248 raise errors.ProgrammerError("Architecture information hasn't been" 249 " initialized") 250 251 return _arch
252 253
254 -def GetClient(query=True):
255 """Connects to the a luxi socket and returns a client. 256 257 @type query: boolean 258 @param query: this signifies that the client will only be 259 used for queries; if the build-time parameter 260 enable-split-queries is enabled, then the client will be 261 connected to the query socket instead of the masterd socket 262 263 """ 264 override_socket = os.getenv(constants.LUXI_OVERRIDE, "") 265 if override_socket: 266 if override_socket == constants.LUXI_OVERRIDE_MASTER: 267 address = pathutils.MASTER_SOCKET 268 elif override_socket == constants.LUXI_OVERRIDE_QUERY: 269 address = pathutils.QUERY_SOCKET 270 else: 271 address = override_socket 272 elif query: 273 address = pathutils.QUERY_SOCKET 274 else: 275 address = None 276 # TODO: Cache object? 277 try: 278 client = luxi.Client(address=address) 279 except NoMasterError: 280 ss = ssconf.SimpleStore() 281 282 # Try to read ssconf file 283 try: 284 ss.GetMasterNode() 285 except errors.ConfigurationError: 286 raise errors.OpPrereqError("Cluster not initialized or this machine is" 287 " not part of a cluster", 288 errors.ECODE_INVAL) 289 290 master, myself = ssconf.GetMasterAndMyself(ss=ss) 291 if master != myself: 292 raise errors.OpPrereqError("This is not the master node, please connect" 293 " to node '%s' and rerun the command" % 294 master, errors.ECODE_INVAL) 295 raise 296 return client
297