# # Copyright (C) 2016 FreeIPA Contributors see COPYING for license # """ serverroles backend ======================================= The `serverroles` backend has access to all roles and attributes stored in module-level lists exposed in `ipaserver/servroles.py` module. It uses these lists to populate populate its internal stores with instances of the roles/attributes. The information contained in them can be accessed by the following methods: *api.Backend.serverroles.server_role_search( server_server=None, role_servrole=None status=None) search for roles matching the given substrings and return the status of the matched roles. Optionally filter the result by role status. If `server_erver` is not None, the search is limited to a single master. Otherwise, the status is computed for all masters in the topology. If `role_servrole` is None, the all configured roled are queried *api.Backend.serverroles.server_role_retrieve(server_server, role_servrole) retrieve the status of a single role on a given master *api.Backend.serverroles.config_retrieve(role_servrole) return a configuration object given role name. This object is a dictionary containing a list of enabled masters and all attributes associated with the role along with master(s) on which they are set. *api.Backend.serverroles.config_update(**attrs_values) update configuration object. Since server roles are currently immutable, only attributes can be set Note that attribute/role names are searched/matched case-insensitively. Also note that the `serverroles` backend does not create/destroy any LDAP connection by itself, so make sure `ldap2` backend connections are taken care of in the calling code """ import six from ipalib import errors, _ from ipalib.backend import Backend from ipalib.plugable import Registry from ipaserver.servroles import ( attribute_instances, ENABLED, HIDDEN, role_instances ) from ipaserver.servroles import SingleValuedServerAttribute if six.PY3: unicode = str register = Registry() @register() class serverroles(Backend): """ This Backend can be used to query various information about server roles and attributes configured in the topology. """ def __init__(self, api_instance): super(serverroles, self).__init__(api_instance) self.role_names = { obj.name.lower(): obj for obj in role_instances} self.attributes = { attr.attr_name: attr for attr in attribute_instances} def _get_role(self, role_name): key = role_name.lower() try: return self.role_names[key] except KeyError: raise errors.NotFound( reason=_("{role}: role not found").format(role=role_name)) def _get_masters(self, role_name, include_hidden): result = {} role = self._get_role(role_name) role_states = role.status(self.api, server=None) enabled_masters = [ r[u'server_server'] for r in role_states if r[u'status'] == ENABLED ] if enabled_masters: result.update({role.attr_name: enabled_masters}) if include_hidden and role.attr_name_hidden is not None: hidden_masters = [ r[u'server_server'] for r in role_states if r[u'status'] == HIDDEN ] if hidden_masters: result.update({role.attr_name_hidden: hidden_masters}) return result def _get_assoc_attributes(self, role_name): role = self._get_role(role_name) assoc_attributes = { name: attr for name, attr in self.attributes.items() if attr.associated_role is role} if not assoc_attributes: raise NotImplementedError( "Role {} has no associated attribute to set".format(role.name)) return assoc_attributes def server_role_search(self, server_server=None, role_servrole=None, status=None): if role_servrole is None: found_roles = self.role_names.values() else: try: found_roles = [self._get_role(role_servrole)] except errors.NotFound: found_roles = [] result = [] for found_role in found_roles: role_status = found_role.status(self.api, server=server_server) result.extend(role_status) if status is not None: return [r for r in result if r[u'status'] == status] return result def server_role_retrieve(self, server_server, role_servrole): return self._get_role(role_servrole).status( self.api, server=server_server) def config_retrieve(self, servrole, include_hidden=True): result = self._get_masters(servrole, include_hidden=include_hidden) try: assoc_attributes = self._get_assoc_attributes(servrole) except NotImplementedError: return result for name, attr in assoc_attributes.items(): attr_value = attr.get(self.api) if attr_value: # attr can be a SingleValuedServerAttribute # in this case, the API expects a value, not a list of values if isinstance(attr, SingleValuedServerAttribute): attr_value = attr_value[0] result.update({name: attr_value}) return result def config_update(self, **attrs_values): for attr, value in attrs_values.items(): try: # when the attribute is single valued, it will be stored # in a SingleValuedServerAttribute. The set method expects # a list containing a single value. # We need to convert value to a list containing value if isinstance(self.attributes[attr], SingleValuedServerAttribute): value = [value] self.attributes[attr].set(self.api, value) except KeyError: raise errors.NotFound( reason=_('{attr}: no such attribute').format(attr=attr))