Files
freeipa/ipaserver/install/plugins/updateclient.py
T
Martin Basti cc19b5a76a Server Upgrade: Apply plugin updates immediately
Preparation to moving plugins executin into update files.
* remove apply_now flag
* plugins will return only (restart, modifications)

https://fedorahosted.org/freeipa/ticket/4904

Reviewed-By: David Kupka <dkupka@redhat.com>
2015-04-14 19:25:47 +02:00

148 lines
4.8 KiB
Python

# Authors: Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2011 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ipaserver.install.plugins.baseupdate import DSRestart
from ipaserver.install.ldapupdate import LDAPUpdate
from ipapython.ipautil import wait_for_open_socket
from ipalib import api
from ipalib import backend
from ipaplatform.paths import paths
from ipapython.dn import DN
class updateclient(backend.Executioner):
"""
Backend used for applying LDAP updates via plugins
An update plugin can be executed before the file-based plugins or
afterward. Each plugin returns three values:
1. restart: dirsrv will be restarted AFTER this update is
applied.
2. updates: A list of updates to be applied.
The value of an update is a dictionary with the following possible
values:
- dn: DN, equal to the dn attribute
- updates: list of updates against the dn
- default: list of the default entry to be added if it doesn't
exist
- deleteentry: list of dn's to be deleted (typically single dn)
For example, this update file:
dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX
replace:krbPwdLockoutDuration:10::600
replace: krbPwdMaxFailure:3::6
Generates this list which contain the update dictionary:
[
dict(
'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com',
'updates': ['replace:krbPwdLockoutDuration:10::600',
'replace:krbPwdMaxFailure:3::6']
)
]
Here is another example showing how a default entry is configured:
dn: cn=Managed Entries,cn=etc,$SUFFIX
default: objectClass: nsContainer
default: objectClass: top
default: cn: Managed Entries
This generates:
[
dict(
'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com',
'default': ['objectClass:nsContainer',
'objectClass:top',
'cn:Managed Entries'
]
)
]
Note that the variable substitution in both examples has been completed.
A PRE_UPDATE plugin is executed before file-based updates.
A POST_UPDATE plugin is executed after file-based updates.
Plugins are executed automatically when ipa-ldap-updater is run
in upgrade mode (--upgrade). They are not executed normally otherwise.
To execute plugins as well use the --plugins flag.
Either may make changes directly in LDAP or can return updates in
update format.
"""
def create_context(self, dm_password):
if dm_password:
autobind = False
else:
autobind = True
self.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password, autobind=autobind)
def order(self, updatetype):
"""Return plugins of the given updatetype in sorted order.
"""
ordered = [plugin for plugin in api.Updater()
if plugin.updatetype == updatetype]
ordered.sort(key=lambda p: p.order)
return ordered
def update(self, updatetype, dm_password, ldapi):
"""
Execute all update plugins of type updatetype.
"""
self.create_context(dm_password)
kw = dict()
result = []
ld = LDAPUpdate(dm_password=dm_password, sub_dict={}, ldapi=ldapi)
for update in self.order(updatetype):
restart, res = self.run(update.name, **kw)
ld.update_from_dict(res)
if restart:
# connection has to be closed before restart, otherwise
# ld instance will try to reuse old non-valid connection
ld.close_connection()
self.restart(dm_password)
self.destroy_context()
return result
def run(self, method, **kw):
"""
Execute the update plugin.
"""
return self.Updater[method](**kw)
def restart(self, dm_password):
dsrestart = DSRestart()
socket_name = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % \
api.env.realm.replace('.','-')
self.destroy_context()
dsrestart.create_instance()
wait_for_open_socket(socket_name)
self.create_context(dm_password)
api.register(updateclient)