| # |
| # |
| |
| # 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 |