From d07b7e0f6fe62eb10edcc7d3a4e884e5c8fd1d29 Mon Sep 17 00:00:00 2001 From: Martin Babinsky Date: Jun 13 2016 15:50:54 +0000 Subject: Server Roles: Backend plugin to query roles and attributes `serverroles` backend consumes the role/attribute instances defined in `ipaserver/servroles.py` module to provide low-level API for querying role/attribute status in the topology. This plugin shall be used to implement higher-level API commands. https://www.freeipa.org/page/V4/Server_Roles https://fedorahosted.org/freeipa/ticket/5181 Reviewed-By: Jan Cholasta Reviewed-By: Martin Basti Reviewed-By: Pavel Vomacka --- diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py new file mode 100644 index 0000000..4a44fca --- /dev/null +++ b/ipaserver/plugins/serverroles.py @@ -0,0 +1,149 @@ +# +# 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, role_instances) + + +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_enabled_masters(self, role_name): + role = self._get_role(role_name) + + enabled_masters = [ + r[u'server_server'] for r in role.status(self.api, server=None) if + r[u'status'] == ENABLED] + + return {role.attr_name: enabled_masters} + + 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): + result = self._get_enabled_masters(servrole) + + try: + assoc_attributes = self._get_assoc_attributes(servrole) + except NotImplementedError: + return result + + result.update( + {name: attr.get(self.api) for name, attr in + assoc_attributes.items()}) + + return result + + def config_update(self, **attrs_values): + for attr, value in attrs_values.items(): + try: + self.attributes[attr].set(self.api, value) + except KeyError: + raise errors.NotFound( + reason=_('{attr}: no such attribute'.format(attr=attr)))