blob: bb586f1c780a7edb947a0304cf54ffebdebdba62 [file] [log] [blame]
#
#
# Copyright (C) 2010 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Module implementing configuration details at runtime.
"""
import grp
import pwd
import threading
import platform
from ganeti import constants
from ganeti import errors
from ganeti import utils
_priv = None
_priv_lock = threading.Lock()
#: Architecture information
_arch = None
def GetUid(user, _getpwnam):
"""Retrieve the uid from the database.
@type user: string
@param user: The username to retrieve
@return: The resolved uid
"""
try:
return _getpwnam(user).pw_uid
except KeyError, err:
raise errors.ConfigurationError("User '%s' not found (%s)" % (user, err))
def GetGid(group, _getgrnam):
"""Retrieve the gid from the database.
@type group: string
@param group: The group name to retrieve
@return: The resolved gid
"""
try:
return _getgrnam(group).gr_gid
except KeyError, err:
raise errors.ConfigurationError("Group '%s' not found (%s)" % (group, err))
class GetentResolver:
"""Resolves Ganeti uids and gids by name.
@ivar masterd_uid: The resolved uid of the masterd user
@ivar masterd_gid: The resolved gid of the masterd group
@ivar confd_uid: The resolved uid of the confd user
@ivar confd_gid: The resolved gid of the confd group
@ivar luxid_uid: The resolved uid of the luxid user
@ivar luxid_gid: The resolved gid of the luxid group
@ivar rapi_uid: The resolved uid of the rapi user
@ivar rapi_gid: The resolved gid of the rapi group
@ivar noded_uid: The resolved uid of the noded user
@ivar daemons_gid: The resolved gid of the daemons group
@ivar admin_gid: The resolved gid of the admin group
"""
def __init__(self, _getpwnam=pwd.getpwnam, _getgrnam=grp.getgrnam):
"""Initialize the resolver.
"""
# Daemon pairs
self.masterd_uid = GetUid(constants.MASTERD_USER, _getpwnam)
self.masterd_gid = GetGid(constants.MASTERD_GROUP, _getgrnam)
self.confd_uid = GetUid(constants.CONFD_USER, _getpwnam)
self.confd_gid = GetGid(constants.CONFD_GROUP, _getgrnam)
self.luxid_uid = GetUid(constants.LUXID_USER, _getpwnam)
self.luxid_gid = GetGid(constants.LUXID_GROUP, _getgrnam)
self.rapi_uid = GetUid(constants.RAPI_USER, _getpwnam)
self.rapi_gid = GetGid(constants.RAPI_GROUP, _getgrnam)
self.noded_uid = GetUid(constants.NODED_USER, _getpwnam)
self.noded_gid = GetGid(constants.NODED_GROUP, _getgrnam)
self.mond_uid = GetUid(constants.MOND_USER, _getpwnam)
self.mond_gid = GetGid(constants.MOND_GROUP, _getgrnam)
# Misc Ganeti groups
self.daemons_gid = GetGid(constants.DAEMONS_GROUP, _getgrnam)
self.admin_gid = GetGid(constants.ADMIN_GROUP, _getgrnam)
self._uid2user = {
self.masterd_uid: constants.MASTERD_USER,
self.confd_uid: constants.CONFD_USER,
self.luxid_uid: constants.LUXID_USER,
self.rapi_uid: constants.RAPI_USER,
self.noded_uid: constants.NODED_USER,
self.mond_uid: constants.MOND_USER,
}
self._gid2group = {
self.masterd_gid: constants.MASTERD_GROUP,
self.confd_gid: constants.CONFD_GROUP,
self.luxid_gid: constants.LUXID_GROUP,
self.rapi_gid: constants.RAPI_GROUP,
self.noded_gid: constants.NODED_GROUP,
self.mond_gid: constants.MOND_GROUP,
self.daemons_gid: constants.DAEMONS_GROUP,
self.admin_gid: constants.ADMIN_GROUP,
}
self._user2uid = utils.InvertDict(self._uid2user)
self._group2gid = utils.InvertDict(self._gid2group)
def LookupUid(self, uid):
"""Looks which Ganeti user belongs to this uid.
@param uid: The uid to lookup
@returns The user name associated with that uid
"""
try:
return self._uid2user[uid]
except KeyError:
raise errors.ConfigurationError("Unknown Ganeti uid '%d'" % uid)
def LookupGid(self, gid):
"""Looks which Ganeti group belongs to this gid.
@param gid: The gid to lookup
@returns The group name associated with that gid
"""
try:
return self._gid2group[gid]
except KeyError:
raise errors.ConfigurationError("Unknown Ganeti gid '%d'" % gid)
def LookupUser(self, name):
"""Looks which uid belongs to this name.
@param name: The name to lookup
@returns The uid associated with that user name
"""
try:
return self._user2uid[name]
except KeyError:
raise errors.ConfigurationError("Unknown Ganeti user '%s'" % name)
def LookupGroup(self, name):
"""Looks which gid belongs to this name.
@param name: The name to lookup
@returns The gid associated with that group name
"""
try:
return self._group2gid[name]
except KeyError:
raise errors.ConfigurationError("Unknown Ganeti group '%s'" % name)
def GetEnts(resolver=GetentResolver):
"""Singleton wrapper around resolver instance.
As this method is accessed by multiple threads at the same time
we need to take thread-safety carefully.
"""
# We need to use the global keyword here
global _priv # pylint: disable=W0603
if not _priv:
_priv_lock.acquire()
try:
if not _priv:
# W0621: Redefine '_priv' from outer scope (used for singleton)
_priv = resolver() # pylint: disable=W0621
finally:
_priv_lock.release()
return _priv
def InitArchInfo():
"""Initialize architecture information.
We can assume this information never changes during the lifetime of a
process, therefore the information can easily be cached.
@note: This function uses C{platform.architecture} to retrieve the Python
binary architecture and does so by forking to run C{file} (see Python
documentation for more information). Therefore it must not be used in a
multi-threaded environment.
"""
global _arch # pylint: disable=W0603
if _arch is not None:
raise errors.ProgrammerError("Architecture information can only be"
" initialized once")
_arch = (platform.architecture()[0], platform.machine())
def GetArchInfo():
"""Returns previsouly initialized architecture information.
"""
if _arch is None:
raise errors.ProgrammerError("Architecture information hasn't been"
" initialized")
return _arch