freeipa/ipaserver/plugins/serverroles.py
Florence Blanc-Renaud a077c705fe
Fix ipa config-mod --ca-renewal-master
commit bddb90f38a added the support for
multivalued server attributes (for pkinit_server_server), but this
introduced an API change where the setter and getter of ServerAttribute
are expecting list of values.

When a SingleValuedServerAttribute is used, we need to convert one elem
into a list containing this elem and vice-versa, so that the ipa config-mod
and ipa config_show APIs are not modified.

https://pagure.io/freeipa/issue/7120

Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
2017-09-05 14:13:46 +02:00

168 lines
5.7 KiB
Python

#
# 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)
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_enabled_masters(self, role_name):
result = {}
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]
if enabled_masters:
result.update({role.attr_name: enabled_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):
result = self._get_enabled_masters(servrole)
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)))