summaryrefslogtreecommitdiffstats
path: root/ipaserver/plugins/serverroles.py
blob: e22eadd7b163469cc9fc4472640aa64d21c9d38f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#
# 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

        for name, attr in assoc_attributes.items():
            attr_value = attr.get(self.api)

            if attr_value is not None:
                result.update({name: attr_value})

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