summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2015-03-18 15:46:00 +0100
committerPetr Vobornik <pvoborni@redhat.com>2015-04-14 19:25:47 +0200
commitf24f614396de809350b54423ca128b478601a64e (patch)
tree7284b80ce5c44ef57f507092e7be312ea082aa61
parentcc19b5a76a37d1fb87deb45d9cbfc71472a99fa4 (diff)
downloadfreeipa-f24f614396de809350b54423ca128b478601a64e.tar.gz
freeipa-f24f614396de809350b54423ca128b478601a64e.tar.xz
freeipa-f24f614396de809350b54423ca128b478601a64e.zip
Server Upgrade: specify order of plugins in update files
* add 'plugin' directive * specify plugins order in update files * remove 'run plugins' options * use ldapupdater API instance in plugins * add update files representing former PreUpdate and PostUpdate order of plugins https://fedorahosted.org/freeipa/ticket/4904 Reviewed-By: David Kupka <dkupka@redhat.com>
-rw-r--r--install/tools/man/ipa-ldap-updater.111
-rw-r--r--install/updates/05-pre_upgrade_plugins.update10
-rw-r--r--install/updates/90-post_upgrade_plugins.update20
-rw-r--r--install/updates/Makefile.am2
-rw-r--r--ipalib/frontend.py6
-rw-r--r--ipaserver/install/dsinstance.py3
-rw-r--r--ipaserver/install/ipa_ldap_updater.py11
-rw-r--r--ipaserver/install/ldapupdate.py184
-rw-r--r--ipaserver/install/plugins/__init__.py6
-rw-r--r--ipaserver/install/plugins/adtrust.py13
-rw-r--r--ipaserver/install/plugins/baseupdate.py32
-rw-r--r--ipaserver/install/plugins/ca_renewal_master.py6
-rw-r--r--ipaserver/install/plugins/dns.py19
-rw-r--r--ipaserver/install/plugins/fix_replica_agreements.py7
-rw-r--r--ipaserver/install/plugins/rename_managed.py11
-rw-r--r--ipaserver/install/plugins/update_idranges.py15
-rw-r--r--ipaserver/install/plugins/update_managed_permissions.py9
-rw-r--r--ipaserver/install/plugins/update_pacs.py9
-rw-r--r--ipaserver/install/plugins/update_passsync.py14
-rw-r--r--ipaserver/install/plugins/update_referint.py9
-rw-r--r--ipaserver/install/plugins/update_services.py8
-rw-r--r--ipaserver/install/plugins/update_uniqueness.py7
-rw-r--r--ipaserver/install/plugins/updateclient.py147
-rw-r--r--ipaserver/install/plugins/upload_cacrt.py8
-rw-r--r--ipaserver/install/upgradeinstance.py2
25 files changed, 235 insertions, 334 deletions
diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1
index 83da26d5d..ce272ea26 100644
--- a/install/tools/man/ipa-ldap-updater.1
+++ b/install/tools/man/ipa-ldap-updater.1
@@ -69,7 +69,11 @@ A few rules:
6. If a DN does exist the default values are skipped
7. Only the first rule on a line is respected
-Adds and updates are applied from shortest to longest length of DN. Deletes are done from longest to shortest.
+ipa-ldap-updater allows to execute update plugins.
+Plugins to be executed are specified with following keyword, in update files:
+ * plugin: name of plugin
+
+This keyword is not bounded to DN, and plugin names have to be registered in API.
Additionally, ipa-ldap-updater can update the schema based on LDIF files.
Any missing object classes and attribute types are added, and differing ones are updated to match the LDIF file.
@@ -81,11 +85,8 @@ Schema files should be in LDIF format, and may only specify attributeTypes and o
\fB\-d\fR, \fB\-\-debug\fR
Enable debug logging when more verbose output is needed
.TP
-\fB\-p\fR, \fB\-\-plugins\fR
-Execute update plugins as well as any update files. There is no way to execute only the plugins.
-.TP
\fB\-u\fR, \fB\-\-upgrade\fR
-Upgrade an installed server in offline mode (implies \-\-ldapi, \-\-plugins, and \-\-schema)
+Upgrade an installed server in offline mode (implies \-\-schema)
.TP
\fB\-s\fR, \fB\-\-schema\fR
Also update the LDAP schema. If no \-\-schema-file is specified, update to the built-in IPA schema.
diff --git a/install/updates/05-pre_upgrade_plugins.update b/install/updates/05-pre_upgrade_plugins.update
new file mode 100644
index 000000000..d0e3eb7ce
--- /dev/null
+++ b/install/updates/05-pre_upgrade_plugins.update
@@ -0,0 +1,10 @@
+# first
+plugin: update_managed_post_first
+
+# middle
+plugin: update_replica_attribute_lists
+plugin: update_passync_privilege_check
+plugin: update_referint
+plugin: update_uniqueness_plugins_to_new_syntax
+
+# last
diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
new file mode 100644
index 000000000..8e8fe0941
--- /dev/null
+++ b/install/updates/90-post_upgrade_plugins.update
@@ -0,0 +1,20 @@
+# first
+
+
+# middle
+plugin: update_dnszones
+plugin: update_dns_limits
+plugin: update_default_range
+plugin: update_default_trust_view
+plugin: update_ca_renewal_master
+plugin: update_idrange_type
+plugin: update_pacs
+plugin: update_service_principalalias
+plugin: update_upload_cacrt
+
+# last
+plugin: update_master_to_dnsforwardzones
+plugin: update_managed_post
+plugin: update_managed_permissions
+plugin: update_idrange_baserid
+plugin: update_passync_privilege_update
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index 40de56356..0d63d9ea8 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -2,6 +2,7 @@ NULL =
appdir = $(IPA_DATA_DIR)/updates
app_DATA = \
+ 05-pre_upgrade_plugins.update \
10-config.update \
10-enable-betxn.update \
10-selinuxusermap.update \
@@ -47,6 +48,7 @@ app_DATA = \
61-trusts-s4u2proxy.update \
62-ranges.update \
71-idviews.update \
+ 90-post_upgrade_plugins.update \
$(NULL)
EXTRA_DIST = \
diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index 36d9ab2d4..19190c378 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -1371,7 +1371,7 @@ class Method(Attribute, Command):
@register.base()
-class Updater(Method):
+class Updater(Plugin):
"""
An LDAP update with an associated object (always update).
@@ -1397,8 +1397,8 @@ class Updater(Method):
>>> api.Updater.my_update # doctest:+ELLIPSIS
ipalib.frontend.my_update()
"""
- def __init__(self):
- super(Updater, self).__init__()
+ def execute(self, **options):
+ raise NotImplementedError('%s.execute()' % self.name)
def __call__(self, **options):
self.debug(
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 523828735..8a76e773f 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -507,7 +507,8 @@ class DsInstance(service.Service):
conn.unbind()
def apply_updates(self):
- ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, sub_dict=self.sub_dict, plugins=True)
+ ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password,
+ sub_dict=self.sub_dict)
files = ld.get_all_files(ldapupdate.UPDATES_DIR)
ld.update(files)
diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py
index 473af961b..c9362ca6d 100644
--- a/ipaserver/install/ipa_ldap_updater.py
+++ b/ipaserver/install/ipa_ldap_updater.py
@@ -48,10 +48,6 @@ class LDAPUpdater(admintool.AdminTool):
parser.add_option("-u", '--upgrade', action="store_true",
dest="upgrade", default=False,
help="upgrade an installed server in offline mode")
- parser.add_option("-p", '--plugins', action="store_true",
- dest="plugins", default=False,
- help="execute update plugins " +
- "(implied when no input files are given)")
parser.add_option("-s", '--schema', action="store_true",
dest="update_schema", default=False,
help="update the schema "
@@ -140,10 +136,6 @@ class LDAPUpdater_NonUpgrade(LDAPUpdater):
def validate_options(self):
super(LDAPUpdater_NonUpgrade, self).validate_options()
- options = self.options
-
- # Only run plugins if no files are given
- self.run_plugins = not self.files or options.plugins
# Need root for running plugins
if os.getegid() != 0:
@@ -167,8 +159,7 @@ class LDAPUpdater_NonUpgrade(LDAPUpdater):
ld = LDAPUpdate(
sub_dict={},
- ldapi=True,
- plugins=options.plugins or self.run_plugins)
+ ldapi=True)
if not self.files:
self.files = ld.get_all_files(UPDATES_DIR)
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index d3e3c3c32..4bb260b33 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -36,13 +36,14 @@ import krbV
import ldap
from ipaserver.install import installutils
+from ipaserver.install.plugins.baseupdate import DSRestart
from ipapython import ipautil, ipaldap
from ipalib import errors
-from ipalib import api
+from ipalib import api, create_api
from ipaplatform.paths import paths
from ipapython.dn import DN
from ipapython.ipa_log_manager import *
-from ipaserver.install.plugins import (PRE_UPDATE, POST_UPDATE)
+from ipapython.ipautil import wait_for_open_socket
from ipaserver.plugins import ldap2
UPDATES_DIR=paths.UPDATES_DIR
@@ -113,7 +114,7 @@ class LDAPUpdate:
action_keywords = ["default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist"]
def __init__(self, dm_password=None, sub_dict={},
- online=True, ldapi=False, plugins=False):
+ online=True, ldapi=False):
'''
:parameters:
dm_password
@@ -124,8 +125,6 @@ class LDAPUpdate:
Do an online LDAP update or use an experimental LDIF updater
ldapi
Bind using ldapi. This assumes autobind is enabled.
- plugins
- execute the pre/post update plugins
Data Structure Example:
-----------------------
@@ -152,6 +151,67 @@ class LDAPUpdate:
The default and update lists are "dispositions"
+ Plugins:
+
+ Plugins has to be specified in update file to be executed, using
+ 'plugin' directive
+
+ Example:
+ plugin: update_uniqueness_plugins_to_new_syntax
+
+ Each plugin returns two 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.
+
+ Either may make changes directly in LDAP or can return updates in
+ update format.
'''
log_mgr.get_logger(self, True)
@@ -161,9 +221,15 @@ class LDAPUpdate:
self.modified = False
self.online = online
self.ldapi = ldapi
- self.plugins = plugins
self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
self.realm = None
+ self.socket_name = (
+ paths.SLAPD_INSTANCE_SOCKET_TEMPLATE %
+ api.env.realm.replace('.', '-')
+ )
+ self.ldapuri = 'ldapi://%s' % ipautil.format_netloc(
+ self.socket_name
+ )
suffix = None
if sub_dict.get("REALM"):
@@ -202,13 +268,14 @@ class LDAPUpdate:
self.sub_dict["TIME"] = int(time.time())
if not self.sub_dict.get("DOMAIN") and domain is not None:
self.sub_dict["DOMAIN"] = domain
-
+ self.api = create_api(mode=None)
+ self.api.bootstrap(in_server=True, context='updates')
+ self.api.finalize()
if online:
# Try out the connection/password
# (This will raise if the server is not available)
self.create_connection()
- self.conn.unbind()
- self.conn = None
+ self.close_connection()
else:
raise RuntimeError("Offline updates are not supported.")
@@ -333,6 +400,13 @@ class LDAPUpdate:
assert isinstance(dn, DN)
all_updates.append(update)
+ def emit_plugin_update(update):
+ '''
+ When processing a plugin is complete emit the plugin update by
+ appending it into list of all updates
+ '''
+ all_updates.append(update)
+
# Iterate over source input lines
for source_line in source_data:
lcount += 1
@@ -344,18 +418,38 @@ class LDAPUpdate:
if source_line.startswith('#') or source_line == '':
continue
+ state = None
+ emit_previous_dn = False
+
+ # parse special keywords
if source_line.lower().startswith('dn:'):
+ state = 'dn'
+ emit_previous_dn = True
+ elif source_line.lower().startswith('plugin:'):
+ state = 'plugin'
+ emit_previous_dn = True
+
+ if emit_previous_dn and dn is not None:
+ # Emit previous dn
+ emit_item(logical_line)
+ logical_line = ''
+ emit_update(update)
+ update = {}
+ dn = None
+
+ if state == 'dn':
# Starting new dn
- if dn is not None:
- # Emit previous dn
- emit_item(logical_line)
- logical_line = ''
- emit_update(update)
- update = {}
-
dn = source_line[3:].strip()
dn = DN(self._template_str(dn))
update['dn'] = dn
+ elif state == 'plugin':
+ # plugin specification is online only
+ plugin_name = source_line[7:].strip()
+ if not plugin_name:
+ raise BadSyntax("plugin name is not defined")
+ update['plugin'] = plugin_name
+ emit_plugin_update(update)
+ update = {}
else:
# Process items belonging to dn
if dn is None:
@@ -589,10 +683,6 @@ class LDAPUpdate:
def _update_record(self, update):
found = False
- # If the entry is going to be deleted no point in processing it.
- if update.has_key('deleteentry'):
- return
-
new_entry = self._create_default_entry(update.get('dn'),
update.get('default'))
@@ -687,9 +777,6 @@ class LDAPUpdate:
and child in the wrong order.
"""
- if not updates.has_key('deleteentry'):
- return
-
dn = updates['dn']
try:
self.info("Deleting entry %s", dn)
@@ -713,20 +800,36 @@ class LDAPUpdate:
f.sort()
return f
+ def _run_update_plugin(self, plugin_name):
+ self.log.info("Executing upgrade plugin: %s", plugin_name)
+ restart_ds, updates = self.api.Updater[plugin_name]()
+ if updates:
+ self._run_updates(updates)
+ # restart may be required even if no updates were returned
+ # from plugin, plugin may change LDAP data directly
+ if restart_ds:
+ self.close_connection()
+ self.restart_ds()
+ self.create_connection()
+
def create_connection(self):
if self.online:
- self.conn = connect(
- ldapi=self.ldapi, realm=self.realm, fqdn=self.sub_dict['FQDN'],
- dm_password=self.dm_password, pw_name=self.pw_name)
+ self.api.Backend.ldap2.connect(
+ bind_dn=DN(('cn', 'Directory Manager')),
+ bind_pw=self.dm_password,
+ autobind=self.ldapi)
+ self.conn = self.api.Backend.ldap2
else:
raise RuntimeError("Offline updates are not supported.")
def _run_updates(self, all_updates):
for update in all_updates:
- self._update_record(update)
-
- for update in all_updates:
- self._delete_record(update)
+ if 'deleteentry' in update:
+ self._delete_record(update)
+ elif 'plugin' in update:
+ self._run_update_plugin(update['plugin'])
+ else:
+ self._update_record(update)
def update(self, files, ordered=True):
"""Execute the update. files is a list of the update files to use.
@@ -738,12 +841,6 @@ class LDAPUpdate:
all_updates = []
try:
self.create_connection()
- if self.plugins:
- self.info('PRE_UPDATE')
- updates = api.Backend.updateclient.update(
- PRE_UPDATE, self.dm_password, self.ldapi)
- # flush out PRE_UPDATE plugin updates before we begin
- self._run_updates(updates)
upgrade_files = files
if ordered:
@@ -760,18 +857,11 @@ class LDAPUpdate:
self.parse_update_file(f, data, all_updates)
self._run_updates(all_updates)
all_updates = []
-
- if self.plugins:
- self.info('POST_UPDATE')
- updates = api.Backend.updateclient.update(
- POST_UPDATE, self.dm_password, self.ldapi)
- self._run_updates(updates)
finally:
self.close_connection()
return self.modified
-
def update_from_dict(self, updates):
"""
Apply updates internally as opposed to from a file.
@@ -788,5 +878,11 @@ class LDAPUpdate:
def close_connection(self):
"""Close ldap connection"""
if self.conn:
- self.conn.unbind()
+ self.api.Backend.ldap2.disconnect()
self.conn = None
+
+ def restart_ds(self):
+ dsrestart = DSRestart()
+
+ dsrestart.create_instance()
+ wait_for_open_socket(self.socket_name)
diff --git a/ipaserver/install/plugins/__init__.py b/ipaserver/install/plugins/__init__.py
index 49bef4df8..6e76841ce 100644
--- a/ipaserver/install/plugins/__init__.py
+++ b/ipaserver/install/plugins/__init__.py
@@ -20,9 +20,3 @@
"""
Provide a separate api for updates.
"""
-PRE_UPDATE = 1
-POST_UPDATE = 2
-
-FIRST = 1
-MIDDLE = 2
-LAST = 4
diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
index 3ad75135d..7a4f543f5 100644
--- a/ipaserver/install/plugins/adtrust.py
+++ b/ipaserver/install/plugins/adtrust.py
@@ -17,22 +17,20 @@
# 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 import MIDDLE
-from ipaserver.install.plugins.baseupdate import PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import *
DEFAULT_ID_RANGE_SIZE = 200000
-class update_default_range(PostUpdate):
+class update_default_range(Updater):
"""
Create default ID range for upgraded servers.
"""
- order=MIDDLE
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
dn = DN(api.env.container_ranges, api.env.basedn)
search_filter = "objectclass=ipaDomainIDRange"
@@ -117,14 +115,13 @@ class update_default_range(PostUpdate):
return False, [update]
-class update_default_trust_view(PostUpdate):
+class update_default_trust_view(Updater):
"""
Create Default Trust View for upgraded servers.
"""
- order = MIDDLE
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
default_trust_view_dn = DN(('cn', 'Default Trust View'),
api.env.container_views,
diff --git a/ipaserver/install/plugins/baseupdate.py b/ipaserver/install/plugins/baseupdate.py
index fa997c9db..d39d8ac89 100644
--- a/ipaserver/install/plugins/baseupdate.py
+++ b/ipaserver/install/plugins/baseupdate.py
@@ -18,9 +18,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ipalib import api
-from ipalib import Updater, Object
+from ipalib import Object
from ipaserver.install import service
-from ipaserver.install.plugins import (PRE_UPDATE, POST_UPDATE, MIDDLE)
class DSRestart(service.Service):
"""
@@ -46,32 +45,3 @@ class DSRestart(service.Service):
self.step("starting directory server", self.start)
self.start_creation(start_message="Restarting Directory server "
"to apply updates", show_service_name=False)
-
-class update(Object):
- """
- Generic object used to register all updates into a single namespace.
- """
- backend_name = 'ldap2'
-
-api.register(update)
-
-
-class PreUpdate(Updater):
- """
- Base class for updates that run prior to file processing.
- """
- updatetype = PRE_UPDATE
- order = MIDDLE
-
- def __init__(self):
- super(PreUpdate, self).__init__()
-
-class PostUpdate(Updater):
- """
- Base class for updates that run after file processing.
- """
- updatetype = POST_UPDATE
- order = MIDDLE
-
- def __init__(self):
- super(PostUpdate, self).__init__()
diff --git a/ipaserver/install/plugins/ca_renewal_master.py b/ipaserver/install/plugins/ca_renewal_master.py
index 3cd1ad240..afbf8129c 100644
--- a/ipaserver/install/plugins/ca_renewal_master.py
+++ b/ipaserver/install/plugins/ca_renewal_master.py
@@ -17,9 +17,9 @@
# 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 PostUpdate
from ipaserver.install import installutils, certs, cainstance
from ipalib import errors
+from ipalib import Updater
from ipalib.plugable import Registry
from ipapython import certmonger, dogtag
from ipaplatform.paths import paths
@@ -28,7 +28,7 @@ from ipapython.dn import DN
register = Registry()
@register()
-class update_ca_renewal_master(PostUpdate):
+class update_ca_renewal_master(Updater):
"""
Set CA renewal master in LDAP.
"""
@@ -39,7 +39,7 @@ class update_ca_renewal_master(PostUpdate):
self.debug("CA is not configured on this host")
return False, []
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
self.api.env.basedn)
filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))'
diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py
index 082c066d0..67c08ccb4 100644
--- a/ipaserver/install/plugins/dns.py
+++ b/ipaserver/install/plugins/dns.py
@@ -24,16 +24,14 @@ import time
from ldif import LDIFWriter
-from ipaserver.install.plugins import MIDDLE, LAST
-from ipaserver.install.plugins.baseupdate import (PostUpdate, PreUpdate)
-from ipaserver.install import sysupgrade
from ipalib import api, errors, util
+from ipalib import Updater
from ipapython.dn import DN
from ipalib.plugins.dns import dns_container_exists
from ipapython.ipa_log_manager import *
-class update_dnszones(PostUpdate):
+class update_dnszones(Updater):
"""
Update all zones to meet requirements in the new FreeIPA versions
@@ -57,10 +55,9 @@ class update_dnszones(PostUpdate):
This module extends the original policy to allow the SSHFP updates.
"""
- order=MIDDLE
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
if not dns_container_exists(ldap):
return False, []
@@ -95,7 +92,7 @@ class update_dnszones(PostUpdate):
api.register(update_dnszones)
-class update_dns_limits(PostUpdate):
+class update_dns_limits(Updater):
"""
bind-dyndb-ldap persistent search queries LDAP for all DNS records.
The LDAP connection must have no size or time limits to work
@@ -106,7 +103,7 @@ class update_dns_limits(PostUpdate):
limit_value = '-1'
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
if not dns_container_exists(ldap):
return False, []
@@ -142,7 +139,7 @@ class update_dns_limits(PostUpdate):
api.register(update_dns_limits)
-class update_master_to_dnsforwardzones(PostUpdate):
+class update_master_to_dnsforwardzones(Updater):
"""
Update all zones to meet requirements in the new FreeIPA versions
@@ -152,14 +149,12 @@ class update_master_to_dnsforwardzones(PostUpdate):
This should be applied only once, and only if original version was lower than 4.0
"""
- order = LAST
-
backup_dir = u'/var/lib/ipa/backup/'
backup_filename = u'dns-forward-zones-backup-%Y-%m-%d-%H-%M-%S.ldif'
backup_path = u'%s%s' % (backup_dir, backup_filename)
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
# check LDAP if forwardzones already uses new semantics
dns_container_dn = DN(api.env.container_dns, api.env.basedn)
try:
diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py
index 98ed9e637..0b1db1c60 100644
--- a/ipaserver/install/plugins/fix_replica_agreements.py
+++ b/ipaserver/install/plugins/fix_replica_agreements.py
@@ -20,23 +20,20 @@
import os
import pwd
from ipapython import ipaldap
-from ipaserver.install.plugins import MIDDLE
-from ipaserver.install.plugins.baseupdate import PreUpdate
from ipaserver.install import replication
from ipalib import api
+from ipalib import Updater
EXCLUDE_TEMPLATE = '(objectclass=*) $ EXCLUDE %s'
-class update_replica_attribute_lists(PreUpdate):
+class update_replica_attribute_lists(Updater):
"""
Run through all replication agreements and ensure that EXCLUDE list
has all the required attributes so that we don't cause replication
storms.
"""
- order = MIDDLE
-
def execute(self, **options):
# We need an IPAdmin connection to the backend
self.log.debug("Start replication agreement exclude list update task")
diff --git a/ipaserver/install/plugins/rename_managed.py b/ipaserver/install/plugins/rename_managed.py
index d3c5bf249..1c031543c 100644
--- a/ipaserver/install/plugins/rename_managed.py
+++ b/ipaserver/install/plugins/rename_managed.py
@@ -17,9 +17,8 @@
# 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 import FIRST, LAST
-from ipaserver.install.plugins.baseupdate import PreUpdate, PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython import ipautil
from ipapython.dn import DN, EditableDN
@@ -47,7 +46,7 @@ class GenerateUpdateMixin(object):
We need to separate the deletes that need to happen from the
new entries that need to be added.
"""
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
suffix = ipautil.realm_to_suffix(api.env.realm)
searchfilter = '(objectclass=*)'
@@ -134,11 +133,10 @@ class GenerateUpdateMixin(object):
return (restart, update_list)
-class update_managed_post_first(PreUpdate, GenerateUpdateMixin):
+class update_managed_post_first(Updater, GenerateUpdateMixin):
"""
Update managed entries
"""
- order=FIRST
def execute(self, **options):
# Never need to restart with the pre-update changes
@@ -148,11 +146,10 @@ class update_managed_post_first(PreUpdate, GenerateUpdateMixin):
api.register(update_managed_post_first)
-class update_managed_post(PostUpdate, GenerateUpdateMixin):
+class update_managed_post(Updater, GenerateUpdateMixin):
"""
Update managed entries
"""
- order=LAST
def execute(self, **options):
(restart, update_list) = self.generate_update(True)
diff --git a/ipaserver/install/plugins/update_idranges.py b/ipaserver/install/plugins/update_idranges.py
index ff061bef7..a6f2527cc 100644
--- a/ipaserver/install/plugins/update_idranges.py
+++ b/ipaserver/install/plugins/update_idranges.py
@@ -17,23 +17,20 @@
# 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 import MIDDLE, LAST
-from ipaserver.install.plugins.baseupdate import PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import *
-class update_idrange_type(PostUpdate):
+class update_idrange_type(Updater):
"""
Update all ID ranges that do not have ipaRangeType attribute filled.
This applies to all ID ranges prior to IPA 3.3.
"""
- order = MIDDLE
-
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
base_dn = DN(api.env.container_ranges, api.env.basedn)
search_filter = ("(&(objectClass=ipaIDrange)(!(ipaRangeType=*)))")
@@ -112,16 +109,14 @@ class update_idrange_type(PostUpdate):
return False, []
-class update_idrange_baserid(PostUpdate):
+class update_idrange_baserid(Updater):
"""
Update ipa-ad-trust-posix ranges' base RID to 0. This applies to AD trust
posix ranges prior to IPA 4.1.
"""
- order = LAST
-
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
base_dn = DN(api.env.container_ranges, api.env.basedn)
search_filter = ("(&(objectClass=ipaTrustedADDomainRange)"
diff --git a/ipaserver/install/plugins/update_managed_permissions.py b/ipaserver/install/plugins/update_managed_permissions.py
index e98523f44..9ca3eac6c 100644
--- a/ipaserver/install/plugins/update_managed_permissions.py
+++ b/ipaserver/install/plugins/update_managed_permissions.py
@@ -89,11 +89,9 @@ from ipalib.plugable import Registry
from ipalib.plugins import aci
from ipalib.plugins.permission import permission, permission_del
from ipalib.aci import ACI
+from ipalib import Updater
from ipapython import ipautil
from ipaserver.plugins.ldap2 import ldap2
-from ipaserver.install.plugins import LAST
-from ipaserver.install.plugins.baseupdate import PostUpdate
-
register = Registry()
@@ -349,14 +347,13 @@ class IncompatibleACIModification(Exception):
@register()
-class update_managed_permissions(PostUpdate):
+class update_managed_permissions(Updater):
"""Update managed permissions after an update.
Update managed permissions according to templates specified in plugins.
For read permissions, puts any attributes specified in the legacy
Anonymous access ACI in the exclude list when creating the permission.
"""
- order = LAST
def get_anonymous_read_aci(self, ldap):
aciname = u'Enable Anonymous access'
@@ -402,7 +399,7 @@ class update_managed_permissions(PostUpdate):
def execute(self, **options):
- ldap = self.api.Backend[ldap2]
+ ldap = self.api.Backend.ldap2
anonymous_read_aci = self.get_anonymous_read_aci(ldap)
diff --git a/ipaserver/install/plugins/update_pacs.py b/ipaserver/install/plugins/update_pacs.py
index ffe6c6670..5f8eec2c8 100644
--- a/ipaserver/install/plugins/update_pacs.py
+++ b/ipaserver/install/plugins/update_pacs.py
@@ -17,21 +17,18 @@
# 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 import MIDDLE
-from ipaserver.install.plugins.baseupdate import PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
-class update_pacs(PostUpdate):
+class update_pacs(Updater):
"""
Includes default nfs:None only if no nfs: PAC present in ipakrbauthzdata.
"""
- order = MIDDLE
-
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
try:
dn = DN('cn=ipaConfig', 'cn=etc', api.env.basedn)
diff --git a/ipaserver/install/plugins/update_passsync.py b/ipaserver/install/plugins/update_passsync.py
index 61c3a77c5..1bda790fc 100644
--- a/ipaserver/install/plugins/update_passsync.py
+++ b/ipaserver/install/plugins/update_passsync.py
@@ -2,15 +2,13 @@
# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
#
-from ipaserver.install.plugins import MIDDLE, LAST
-from ipaserver.install.plugins.baseupdate import PreUpdate, PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
from ipaserver.install import sysupgrade
-class update_passync_privilege_check(PreUpdate):
- order = MIDDLE
+class update_passync_privilege_check(Updater):
def execute(self, **options):
update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated')
@@ -24,7 +22,7 @@ class update_passync_privilege_check(PreUpdate):
self.api.env.container_privilege,
self.api.env.basedn)
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
try:
ldap.get_entry(passsync_privilege_dn, [''])
except errors.NotFound:
@@ -38,13 +36,11 @@ class update_passync_privilege_check(PreUpdate):
api.register(update_passync_privilege_check)
-class update_passync_privilege_update(PostUpdate):
+class update_passync_privilege_update(Updater):
"""
Add PassSync user as a member of PassSync privilege, if it exists
"""
- order = LAST
-
def execute(self, **options):
update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated')
if update_done:
@@ -52,7 +48,7 @@ class update_passync_privilege_update(PostUpdate):
return False, []
root_logger.debug("Add PassSync user as a member of PassSync privilege")
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
passsync_dn = DN(('uid','passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'),
api.env.basedn)
passsync_privilege_dn = DN(('cn','PassSync Service'),
diff --git a/ipaserver/install/plugins/update_referint.py b/ipaserver/install/plugins/update_referint.py
index aa3a4a3fa..960a5ad1a 100644
--- a/ipaserver/install/plugins/update_referint.py
+++ b/ipaserver/install/plugins/update_referint.py
@@ -2,13 +2,12 @@
# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
#
-from ipaserver.install.plugins import MIDDLE
-from ipaserver.install.plugins.baseupdate import PreUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
-class update_referint(PreUpdate):
+class update_referint(Updater):
"""
Update referential integrity configuration to new style
http://directory.fedoraproject.org/docs/389ds/design/ri-plugin-configuration.html
@@ -22,15 +21,13 @@ class update_referint(PreUpdate):
Old and new style cannot be mixed, all nslapd-pluginArg* attrs have to be removed
"""
- order = MIDDLE
-
referint_dn = DN(('cn', 'referential integrity postoperation'),
('cn', 'plugins'), ('cn', 'config'))
def execute(self, **options):
root_logger.debug("Upgrading referential integrity plugin configuration")
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
try:
entry = ldap.get_entry(self.referint_dn)
except errors.NotFound:
diff --git a/ipaserver/install/plugins/update_services.py b/ipaserver/install/plugins/update_services.py
index 1de856885..490d0748b 100644
--- a/ipaserver/install/plugins/update_services.py
+++ b/ipaserver/install/plugins/update_services.py
@@ -17,23 +17,21 @@
# 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 import MIDDLE
-from ipaserver.install.plugins.baseupdate import PostUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import *
-class update_service_principalalias(PostUpdate):
+class update_service_principalalias(Updater):
"""
Update all services which do not have ipakrbprincipalalias attribute
used for case-insensitive principal searches filled. This applies for
all services created prior IPA 3.0.
"""
- order = MIDDLE
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
base_dn = DN(api.env.container_service, api.env.basedn)
search_filter = ("(&(objectclass=krbprincipal)(objectclass=ipaservice)"
diff --git a/ipaserver/install/plugins/update_uniqueness.py b/ipaserver/install/plugins/update_uniqueness.py
index fa6b990e0..53cab6d31 100644
--- a/ipaserver/install/plugins/update_uniqueness.py
+++ b/ipaserver/install/plugins/update_uniqueness.py
@@ -17,14 +17,13 @@
# 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 import MIDDLE
-from ipaserver.install.plugins.baseupdate import PostUpdate, PreUpdate
from ipalib import api, errors
+from ipalib import Updater
from ipapython.dn import DN
from ipapython.ipa_log_manager import *
-class update_uniqueness_plugins_to_new_syntax(PreUpdate):
+class update_uniqueness_plugins_to_new_syntax(Updater):
"""
Migrate uniqueness plugins to new style syntax
@@ -165,7 +164,7 @@ class update_uniqueness_plugins_to_new_syntax(PreUpdate):
return update
def execute(self, **options):
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
old_style_plugin_search_filter = (
"(&"
diff --git a/ipaserver/install/plugins/updateclient.py b/ipaserver/install/plugins/updateclient.py
deleted file mode 100644
index 782ad0eda..000000000
--- a/ipaserver/install/plugins/updateclient.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# 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)
diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py
index c9c3c9f9c..db34e1cb7 100644
--- a/ipaserver/install/plugins/upload_cacrt.py
+++ b/ipaserver/install/plugins/upload_cacrt.py
@@ -17,18 +17,16 @@
# 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 import MIDDLE
-from ipaserver.install.plugins.baseupdate import PostUpdate
from ipaserver.install import certs
from ipalib import api, errors, certstore
+from ipalib import Updater
from ipapython import certdb
from ipapython.dn import DN
-class update_upload_cacrt(PostUpdate):
+class update_upload_cacrt(Updater):
"""
Upload public CA certificate to LDAP
"""
- order=MIDDLE
def execute(self, **options):
db = certs.CertDB(self.api.env.realm)
@@ -45,7 +43,7 @@ class update_upload_cacrt(PostUpdate):
if ca_chain:
ca_nickname = ca_chain[-1]
- ldap = self.obj.backend
+ ldap = self.api.Backend.ldap2
for nickname, trust_flags in db.list_certs():
if 'u' in trust_flags:
diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py
index 2f9039dd7..160b735c8 100644
--- a/ipaserver/install/upgradeinstance.py
+++ b/ipaserver/install/upgradeinstance.py
@@ -126,7 +126,7 @@ class IPAUpgrade(service.Service):
def __upgrade(self):
try:
- ld = ldapupdate.LDAPUpdate(dm_password='', ldapi=True, plugins=True)
+ ld = ldapupdate.LDAPUpdate(dm_password='', ldapi=True)
if len(self.files) == 0:
self.files = ld.get_all_files(ldapupdate.UPDATES_DIR)
self.modified = (ld.update(self.files) or self.modified)