summaryrefslogtreecommitdiffstats
path: root/ipaserver/install/plugins/update_dna_shared_config.py
blob: 21ed9c4a947bc65ce9bec11ed2563e52878bcaa7 (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
#
# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
#

import time
import ldap

from ipalib.plugable import Registry
from ipalib import errors
from ipalib import Updater
from ipapython.dn import DN

register = Registry()


@register()
class update_dna_shared_config(Updater):
    def execute(self, **options):
        method = options.get('method', "SASL/GSSAPI")
        protocol = options.get('protocol', "LDAP")

        dna_bind_method = "dnaRemoteBindMethod"
        dna_conn_protocol = "dnaRemoteConnProtocol"
        dna_plugin = DN(('cn', 'Distributed Numeric Assignment Plugin'),
                        ('cn', 'plugins'),
                        ('cn', 'config'))
        dna_config_base = DN(('cn', 'posix IDs'), dna_plugin)

        conn = self.api.Backend.ldap2

        # Check the plugin is enabled else it is useless to update
        # the shared entry
        try:
            entry = conn.get_entry(dna_plugin)
            if entry.single_value.get('nsslapd-pluginenabled') == 'off':
                return False, ()
        except errors.NotFound:
            self.log.error("Could not find DNA plugin entry: %s" %
                           dna_config_base)
            return False, ()

        try:
            entry = conn.get_entry(dna_config_base)
        except errors.NotFound:
            self.log.error("Could not find DNA config entry: %s" %
                           dna_config_base)
            return False, ()

        sharedcfgdn = entry.single_value.get("dnaSharedCfgDN")
        if sharedcfgdn is not None:
            sharedcfgdn = DN(sharedcfgdn)
        else:
            self.log.error(
                "Could not find DNA shared config DN in entry: %s" %
                dna_config_base)
            return False, ()

        #
        # Update the shared config entry related to that host
        #
        # If the shared config entry already exists (like upgrade)
        # the update occurs immediately without sleep.
        #
        # If the shared config entry does not exist (fresh install)
        # DS server waits for 30s after its startup to create it.
        # Startup likely occurred few sec before this function is
        # called so this loop will wait for 30s max.
        #
        # In case the server is not able to create the entry
        # The loop gives a grace period of 60s before logging
        # the failure to update the shared config entry and return
        #
        max_wait = 30
        fqdn = self.api.env.host
        for _i in range(0, max_wait + 1):
            try:
                entries = conn.get_entries(
                    sharedcfgdn, scope=ldap.SCOPE_ONELEVEL,
                    filter='dnaHostname=%s' % fqdn
                )
                break
            except errors.NotFound:
                self.log.debug(
                    "Unable to find DNA shared config entry for "
                    "dnaHostname=%s (under %s) so far. Retry in 2 sec." %
                    (fqdn, sharedcfgdn)
                )
                time.sleep(2)
        else:
            self.log.error(
                "Could not get dnaHostname entries in {} seconds".format(
                    max_wait * 2)
            )
            return False, ()

        # If there are several entries, all of them will be updated
        # just log a debug msg. This is likely the result of #5510
        if len(entries) != 1:
            self.log.debug(
                "%d entries dnaHostname=%s under %s. One expected" %
                (len(entries), fqdn, sharedcfgdn)
            )

        # time to set the bind method and the protocol in the
        # shared config entries
        for entry in entries:
            update = False
            if entry.single_value.get(dna_bind_method) != method:
                entry[dna_bind_method] = method
                update = True

            if entry.single_value.get(dna_conn_protocol) != protocol:
                entry[dna_conn_protocol] = protocol
                update = True

            if update:
                try:
                    conn.update_entry(entry)
                except Exception as e:
                    self.log.error(
                        "Failed to set SASL/GSSAPI bind method/protocol "
                        "in entry {}: {}".format(entry, e)
                    )
        # no restart, no update
        return False, ()