Hello, The patches: * allows to specify order of update plugins in update files. * requires to use LDAPI by ipa-ldap-updater
patches attached -- Martin Basti
From 6093015bc4465fa3ec20038fb246d32309e36ef7 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 17 Mar 2015 16:11:48 +0100 Subject: [PATCH 1/9] Server Upgrade: use only LDAPI connection Use only ldapi connection to execute upgrade https://fedorahosted.org/freeipa/ticket/4904 --- install/tools/man/ipa-ldap-updater.1 | 9 --------- ipaserver/install/ipa_ldap_updater.py | 33 ++------------------------------- ipaserver/install/ldapupdate.py | 2 +- 3 files changed, 3 insertions(+), 41 deletions(-) diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1 index 5ab77e047d523975caeb13943d9a14069f1c3a6d..83da26d5da70551c23ea636184e1b2ce98d374c2 100644 --- a/install/tools/man/ipa-ldap-updater.1 +++ b/install/tools/man/ipa-ldap-updater.1 @@ -81,21 +81,12 @@ 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\-y\fR -File containing the Directory Manager password -.TP -\fB\-l\fR, \fB\-\-ldapi\fR -Connect to the LDAP server using the ldapi socket -.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) .TP -\fB\-W\fR, \fB\-\-password\fR -Prompt for the Directory Manager password -.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. .TP diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index 3d6c8043764d7f5ad398bf43606927e3a7b8bb1a..95688c591a244dccefdb2bd8341b482e60d206a8 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -45,12 +45,6 @@ class LDAPUpdater(admintool.AdminTool): @classmethod def add_options(cls, parser): super(LDAPUpdater, cls).add_options(parser, debug_option=True) - - parser.add_option("-y", dest="password", - help="file containing the Directory Manager password") - parser.add_option("-l", '--ldapi', action="store_true", dest="ldapi", - default=False, - help="connect to the LDAP server using the ldapi socket") parser.add_option("-u", '--upgrade', action="store_true", dest="upgrade", default=False, help="upgrade an installed server in offline mode") @@ -65,9 +59,6 @@ class LDAPUpdater(admintool.AdminTool): parser.add_option("-S", '--schema-file', action="append", dest="schema_files", help="custom schema ldif file to use (implies -s)") - parser.add_option("-W", '--password', action="store_true", - dest="ask_password", - help="prompt for the Directory Manager password") @classmethod def get_command_class(cls, options, args): @@ -96,12 +87,6 @@ class LDAPUpdater(admintool.AdminTool): print "IPA is not configured on this system." sys.exit(1) - if options.password: - pw = ipautil.template_file(options.password, []) - self.dirman_password = pw.strip() - else: - self.dirman_password = None - if options.schema_files or not self.files: options.update_schema = True if not options.schema_files: @@ -171,18 +156,6 @@ class LDAPUpdater_NonUpgrade(LDAPUpdater): # Can't log to the default file as non-root self.log_file_name = None - def ask_for_options(self): - super(LDAPUpdater_NonUpgrade, self).ask_for_options() - options = self.options - if not self.dirman_password: - if options.ask_password or not options.ldapi: - password = installutils.read_password("Directory Manager", - confirm=False, validate=False) - if password is None: - raise admintool.ScriptError( - "Directory Manager password required") - self.dirman_password = password - def run(self): super(LDAPUpdater_NonUpgrade, self).run() options = self.options @@ -192,13 +165,11 @@ class LDAPUpdater_NonUpgrade(LDAPUpdater): if options.update_schema: modified = schemaupdate.update_schema( options.schema_files, - dm_password=self.dirman_password, - ldapi=options.ldapi) or modified + ldapi=True) or modified ld = LDAPUpdate( - dm_password=self.dirman_password, sub_dict={}, - ldapi=options.ldapi, + ldapi=True, plugins=options.plugins or self.run_plugins) if not self.files: diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 199b23ba8ec0c7d040a4be260440476f1a1e65a8..077de3bd68571fee4a227b456bb5f6ea09f352cd 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -112,7 +112,7 @@ def safe_output(attr, values): class LDAPUpdate: action_keywords = ["default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist"] - def __init__(self, dm_password, sub_dict={}, + def __init__(self, dm_password=None, sub_dict={}, online=True, ldapi=False, plugins=False): ''' :parameters: -- 2.1.0
From 5e6e0679ed080415a68dfa4303e9469b7af7f341 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 17 Mar 2015 16:53:44 +0100 Subject: [PATCH 2/9] Server Upgrade: remove unused code in upgrade https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/ipa_ldap_updater.py | 2 -- ipaserver/install/ldapupdate.py | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index 95688c591a244dccefdb2bd8341b482e60d206a8..473af961b6f98736d189bdc30ddf70afda922659 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -119,12 +119,10 @@ class LDAPUpdater_Upgrade(LDAPUpdater): super(LDAPUpdater_Upgrade, self).run() options = self.options - updates = None realm = krbV.default_context().default_realm upgrade = IPAUpgrade(realm, self.files, schema_files=options.schema_files) upgrade.create_instance() - upgradefailed = upgrade.upgradefailed if upgrade.badsyntax: raise admintool.ScriptError( diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 077de3bd68571fee4a227b456bb5f6ea09f352cd..d3e3c3c325fc9c88f48330999111450a6fe688a3 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -185,16 +185,11 @@ class LDAPUpdate: fqdn = installutils.get_fqdn() if fqdn is None: raise RuntimeError("Unable to determine hostname") - fqhn = fqdn # Save this for the sub_dict variable - if self.ldapi: - fqdn = "ldapi://%%2fvar%%2frun%%2fslapd-%s.socket" % "-".join( - self.realm.split(".") - ) if not self.sub_dict.get("REALM") and self.realm is not None: self.sub_dict["REALM"] = self.realm if not self.sub_dict.get("FQDN"): - self.sub_dict["FQDN"] = fqhn + self.sub_dict["FQDN"] = fqdn if not self.sub_dict.get("DOMAIN"): self.sub_dict["DOMAIN"] = domain if not self.sub_dict.get("SUFFIX") and suffix is not None: @@ -279,7 +274,6 @@ class LDAPUpdate: for each DN in the file.""" update = {} logical_line = "" - action = "" dn = None lcount = 0 -- 2.1.0
From 86a311f81068ea30e34dc84a3f38692e22569486 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Tue, 17 Mar 2015 17:56:34 +0100 Subject: [PATCH 3/9] 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 --- ipaserver/install/plugins/adtrust.py | 12 ++++----- ipaserver/install/plugins/ca_renewal_master.py | 16 ++++++------ ipaserver/install/plugins/dns.py | 30 +++++++++++----------- .../install/plugins/fix_replica_agreements.py | 2 +- ipaserver/install/plugins/rename_managed.py | 4 +-- ipaserver/install/plugins/update_idranges.py | 18 ++++++------- .../install/plugins/update_managed_permissions.py | 2 +- ipaserver/install/plugins/update_pacs.py | 4 +-- ipaserver/install/plugins/update_passsync.py | 10 ++++---- ipaserver/install/plugins/update_referint.py | 8 +++--- ipaserver/install/plugins/update_services.py | 12 ++++----- ipaserver/install/plugins/update_uniqueness.py | 4 +-- ipaserver/install/plugins/updateclient.py | 17 ++++-------- ipaserver/install/plugins/upload_cacrt.py | 2 +- 14 files changed, 67 insertions(+), 74 deletions(-) diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py index dbec429aa4890d0a3eeef1ea3ed4524ecbcb39e8..3ad75135ddb1e3ef253563446d7cf4185cf12484 100644 --- a/ipaserver/install/plugins/adtrust.py +++ b/ipaserver/install/plugins/adtrust.py @@ -42,7 +42,7 @@ class update_default_range(PostUpdate): pass else: root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin") - return (False, False, []) + return False, [] dn = DN(('cn', 'admins'), api.env.container_group, api.env.basedn) try: @@ -50,7 +50,7 @@ class update_default_range(PostUpdate): except errors.NotFound: root_logger.error("default_range: No local ID range and no admins " "group found. Cannot create default ID range") - return (False, False, []) + return False, [] id_range_base_id = admins_entry['gidnumber'][0] id_range_name = '%s_id_range' % api.env.realm @@ -114,7 +114,7 @@ class update_default_range(PostUpdate): root_logger.error("default_range: %s", "\n".join(msg)) - return (False, True, [update]) + return False, [update] class update_default_trust_view(PostUpdate): @@ -141,7 +141,7 @@ class update_default_trust_view(PostUpdate): # First, see if trusts are enabled on the server if not self.api.Command.adtrust_is_enabled()['result']: self.log.info('AD Trusts are not enabled on this server') - return (False, False, []) + return False, [] # Second, make sure the Default Trust View does not exist yet try: @@ -150,7 +150,7 @@ class update_default_trust_view(PostUpdate): pass else: self.log.info('Default Trust View already present on this server') - return (False, False, []) + return False, [] # We have a server with AD trust support without Default Trust View. # Create the Default Trust View entry. @@ -160,7 +160,7 @@ class update_default_trust_view(PostUpdate): 'default': default_trust_view_entry } - return (False, True, [update]) + return False, [update] api.register(update_default_range) api.register(update_default_trust_view) diff --git a/ipaserver/install/plugins/ca_renewal_master.py b/ipaserver/install/plugins/ca_renewal_master.py index b0fb527a3e02364bb3593ff3068ae510c4ff051e..3cd1ad240413f84ab4217d282949b930b577dc05 100644 --- a/ipaserver/install/plugins/ca_renewal_master.py +++ b/ipaserver/install/plugins/ca_renewal_master.py @@ -37,7 +37,7 @@ class update_ca_renewal_master(PostUpdate): ca = cainstance.CAInstance(self.api.env.realm, certs.NSS_DIR) if not ca.is_configured(): self.debug("CA is not configured on this host") - return (False, False, []) + return False, [] ldap = self.obj.backend base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), @@ -50,7 +50,7 @@ class update_ca_renewal_master(PostUpdate): pass else: self.debug("found CA renewal master %s", entries[0].dn[1].value) - return (False, False, []) + return False, [] criteria = { 'cert-database': paths.HTTPD_ALIAS_DIR, @@ -65,20 +65,20 @@ class update_ca_renewal_master(PostUpdate): self.warning( "certmonger request for ipaCert is missing ca_name, " "assuming local CA is renewal slave") - return (False, False, []) + return False, [] ca_name = ca_name.strip() if ca_name == 'dogtag-ipa-renew-agent': pass elif ca_name == 'dogtag-ipa-retrieve-agent-submit': - return (False, False, []) + return False, [] elif ca_name == 'dogtag-ipa-ca-renew-agent': - return (False, False, []) + return False, [] else: self.warning( "certmonger request for ipaCert has unknown ca_name '%s', " "assuming local CA is renewal slave", ca_name) - return (False, False, []) + return False, [] else: self.debug("certmonger request for ipaCert not found") @@ -89,7 +89,7 @@ class update_ca_renewal_master(PostUpdate): if config == 'New': pass elif config == 'Clone': - return (False, False, []) + return False, [] else: self.warning( "CS.cfg has unknown subsystem.select value '%s', " @@ -102,4 +102,4 @@ class update_ca_renewal_master(PostUpdate): 'updates': ['add:ipaConfigString: caRenewalMaster'], } - return (False, True, [update]) + return False, [update] diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py index f562978bcbcc02321c0e9a668af88b4f596f8556..082c066d0f270242ffa4844a51ec82272e31b5e9 100644 --- a/ipaserver/install/plugins/dns.py +++ b/ipaserver/install/plugins/dns.py @@ -62,13 +62,13 @@ class update_dnszones(PostUpdate): def execute(self, **options): ldap = self.obj.backend if not dns_container_exists(ldap): - return (False, False, []) + return False, [] try: zones = api.Command.dnszone_find(all=True)['result'] except errors.NotFound: self.log.info('No DNS zone to update found') - return (False, False, []) + return False, [] for zone in zones: update = {} @@ -90,7 +90,7 @@ class update_dnszones(PostUpdate): api.Command.dnszone_mod(zone[u'idnsname'][0].make_absolute(), **update) - return (False, False, []) + return False, [] api.register(update_dnszones) @@ -109,7 +109,7 @@ class update_dns_limits(PostUpdate): ldap = self.obj.backend if not dns_container_exists(ldap): - return (False, False, []) + return False, [] dns_principal = 'DNS/%s@%s' % (self.env.host, self.env.realm) dns_service_dn = DN(('krbprincipalname', dns_principal), @@ -121,12 +121,12 @@ class update_dns_limits(PostUpdate): except errors.NotFound: # this host may not have DNS service set root_logger.debug("DNS: service %s not found, no need to update limits" % dns_service_dn) - return (False, False, []) + return False, [] if all(entry.get(limit.lower(), [None])[0] == self.limit_value for limit in self.limit_attributes): root_logger.debug("DNS: limits for service %s already set" % dns_service_dn) # service is already updated - return (False, False, []) + return False, [] limit_updates = [] @@ -137,7 +137,7 @@ class update_dns_limits(PostUpdate): root_logger.debug("DNS: limits for service %s will be updated" % dns_service_dn) - return (False, True, [dnsupdate]) + return False, [dnsupdate] api.register(update_dns_limits) @@ -166,7 +166,7 @@ class update_master_to_dnsforwardzones(PostUpdate): container_entry = ldap.get_entry(dns_container_dn) except errors.NotFound: # DNS container not found, nothing to upgrade - return (False, False, []) + return False, [] for config_option in container_entry.get("ipaConfigString", []): matched = re.match("^DNSVersion\s+(?P<version>\d+)$", @@ -174,7 +174,7 @@ class update_master_to_dnsforwardzones(PostUpdate): if matched and int(matched.group("version")) >= 1: # forwardzones already uses new semantics, # no upgrade is required - return (False, False, []) + return False, [] self.log.info('Updating forward zones') # update the DNSVersion, following upgrade can be executed only once @@ -193,7 +193,7 @@ class update_master_to_dnsforwardzones(PostUpdate): else: if fwzones: # fwzones exist, do not execute upgrade again - return (False, False, []) + return False, [] zones = [] try: @@ -206,7 +206,7 @@ class update_master_to_dnsforwardzones(PostUpdate): if not zones: self.log.info('No DNS zone to update found') - return (False, False, []) + return False, [] zones_to_transform = [] @@ -271,7 +271,7 @@ class update_master_to_dnsforwardzones(PostUpdate): self.log.error('Unable to backup zone %s' % zone['idnsname'][0]) self.log.error(traceback.format_exc()) - return (False, False, []) + return False, [] for privilege_dn in privileges_to_ldif: try: @@ -281,13 +281,13 @@ class update_master_to_dnsforwardzones(PostUpdate): self.log.error('Unable to backup privilege %s' % privilege_dn) self.log.error(traceback.format_exc()) - return (False, False, []) + return False, [] f.close() except Exception: self.log.error('Unable to create backup file') self.log.error(traceback.format_exc()) - return (False, False, []) + return False, [] # update for zone in zones_to_transform: @@ -352,6 +352,6 @@ class update_master_to_dnsforwardzones(PostUpdate): self.log.info('Zone %s was sucessfully transformed to forward zone', zone['idnsname'][0]) - return (False, False, []) + return False, [] api.register(update_master_to_dnsforwardzones) diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py index a5ff4819fa4c432b378a9f1c0f6952bc312a6792..98ed9e6379179a89e68ba8153b6ba27e389efd38 100644 --- a/ipaserver/install/plugins/fix_replica_agreements.py +++ b/ipaserver/install/plugins/fix_replica_agreements.py @@ -65,7 +65,7 @@ class update_replica_attribute_lists(PreUpdate): self.log.debug("Done updating agreements") - return (False, False, []) # No restart, no apply now, no updates + return False, [] # No restart, no updates def _update_attr(self, repl, replica, attribute, values, template='%s'): """Add or update an attribute of a replication agreement diff --git a/ipaserver/install/plugins/rename_managed.py b/ipaserver/install/plugins/rename_managed.py index adb814c1799ebbdb57118acf1ba6a52550f2f818..d3c5bf249e04a09ef9111f21a66becf5f95c2a8d 100644 --- a/ipaserver/install/plugins/rename_managed.py +++ b/ipaserver/install/plugins/rename_managed.py @@ -144,7 +144,7 @@ class update_managed_post_first(PreUpdate, GenerateUpdateMixin): # Never need to restart with the pre-update changes (ignore, update_list) = self.generate_update(False) - return (False, True, update_list) + return False, update_list api.register(update_managed_post_first) @@ -157,6 +157,6 @@ class update_managed_post(PostUpdate, GenerateUpdateMixin): def execute(self, **options): (restart, update_list) = self.generate_update(True) - return (restart, True, update_list) + return restart, update_list api.register(update_managed_post) diff --git a/ipaserver/install/plugins/update_idranges.py b/ipaserver/install/plugins/update_idranges.py index 1aa5fa7631fd35a7aaf4a23a5eee44e4e0a2e904..ff061bef702e77ae3be21e9614262d970e234f1f 100644 --- a/ipaserver/install/plugins/update_idranges.py +++ b/ipaserver/install/plugins/update_idranges.py @@ -51,18 +51,18 @@ class update_idrange_type(PostUpdate): except errors.NotFound: root_logger.debug("update_idrange_type: no ID range without " "type set found") - return (False, False, []) + return False, [] except errors.ExecutionError, e: root_logger.error("update_idrange_type: cannot retrieve list " "of ranges with no type set: %s", e) - return (False, False, []) + return False, [] if not entries: # No entry was returned, rather break than continue cycling root_logger.debug("update_idrange_type: no ID range was " "returned") - return (False, False, []) + return False, [] root_logger.debug("update_idrange_type: found %d " "idranges to update, truncated: %s", @@ -101,15 +101,15 @@ class update_idrange_type(PostUpdate): # Exit loop to avoid infinite cycles root_logger.error("update_idrange_type: error(s) " "detected during idrange type update") - return (False, False, []) + return False, [] elif not truncated: # All affected entries updated, exit the loop root_logger.debug("update_idrange_type: all affected idranges " "were assigned types") - return (False, False, []) + return False, [] - return (False, False, []) + return False, [] class update_idrange_baserid(PostUpdate): @@ -140,12 +140,12 @@ class update_idrange_baserid(PostUpdate): except errors.NotFound: root_logger.debug("update_idrange_baserid: no AD domain " "range with posix attributes found") - return (False, False, []) + return False, [] except errors.ExecutionError, e: root_logger.error("update_idrange_baserid: cannot retrieve " "list of affected ranges: %s", e) - return (False, False, []) + return False, [] root_logger.debug("update_idrange_baserid: found %d " "idranges possible to update", @@ -175,7 +175,7 @@ class update_idrange_baserid(PostUpdate): root_logger.debug("update_idrange_baserid: all affected " "idranges updated") - return (False, False, []) + return False, [] api.register(update_idrange_type) api.register(update_idrange_baserid) diff --git a/ipaserver/install/plugins/update_managed_permissions.py b/ipaserver/install/plugins/update_managed_permissions.py index 430a2919a315bfd8d8e6174a915890d44b782c5c..e98523f442c1ae7b87ca92ba7e7846859da15087 100644 --- a/ipaserver/install/plugins/update_managed_permissions.py +++ b/ipaserver/install/plugins/update_managed_permissions.py @@ -441,7 +441,7 @@ class update_managed_permissions(PostUpdate): else: self.log.info('Obsolete permission deleted: %s', obsolete_name) - return False, False, () + return False, () def update_permission(self, ldap, obj, name, template, anonymous_read_aci): """Update the given permission and the corresponding ACI""" diff --git a/ipaserver/install/plugins/update_pacs.py b/ipaserver/install/plugins/update_pacs.py index 653456bb84d5464022024f5baaf4a7543f01f96f..ffe6c667015423d4c465f2a3e9778ab99fbf8432 100644 --- a/ipaserver/install/plugins/update_pacs.py +++ b/ipaserver/install/plugins/update_pacs.py @@ -39,7 +39,7 @@ class update_pacs(PostUpdate): pacs = entry.get('ipakrbauthzdata', []) except errors.NotFound: self.log.warning('Error retrieving: %s' % str(dn)) - return (False, False, []) + return False, [] nfs_pac_set = any(pac.startswith('nfs:') for pac in pacs) @@ -52,6 +52,6 @@ class update_pacs(PostUpdate): else: self.log.debug('PAC for nfs is already set, not adding nfs:NONE.') - return (False, False, []) + return False, [] api.register(update_pacs) diff --git a/ipaserver/install/plugins/update_passsync.py b/ipaserver/install/plugins/update_passsync.py index e0d2fc01cbc66af24cb908b80d3a031903fdc463..61c3a77c532bb8e56e5c6bec611058df96bf2338 100644 --- a/ipaserver/install/plugins/update_passsync.py +++ b/ipaserver/install/plugins/update_passsync.py @@ -16,7 +16,7 @@ class update_passync_privilege_check(PreUpdate): update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated') if update_done: root_logger.debug("PassSync privilege update pre-check not needed") - return False, False, [] + return False, [] root_logger.debug("Check if there is existing PassSync privilege") @@ -34,7 +34,7 @@ class update_passync_privilege_check(PreUpdate): root_logger.debug("PassSync privilege found, skip updating PassSync") sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) - return False, False, [] + return False, [] api.register(update_passync_privilege_check) @@ -49,7 +49,7 @@ class update_passync_privilege_update(PostUpdate): update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated') if update_done: root_logger.debug("PassSync privilege update not needed") - return False, False, [] + return False, [] root_logger.debug("Add PassSync user as a member of PassSync privilege") ldap = self.obj.backend @@ -64,7 +64,7 @@ class update_passync_privilege_update(PostUpdate): except errors.NotFound: root_logger.debug("PassSync user not found, no update needed") sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) - return False, False, [] + return False, [] else: root_logger.debug("PassSync user found, do update") @@ -72,6 +72,6 @@ class update_passync_privilege_update(PostUpdate): 'updates': ["add:member:'%s'" % passsync_dn]} sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) - return (False, True, [update]) + return False, [update] api.register(update_passync_privilege_update) diff --git a/ipaserver/install/plugins/update_referint.py b/ipaserver/install/plugins/update_referint.py index 1b7411035b27ebba04246a7ee6f220d470b46688..aa3a4a3fa3e98abb23d74f9be0354a5cbad38d7e 100644 --- a/ipaserver/install/plugins/update_referint.py +++ b/ipaserver/install/plugins/update_referint.py @@ -35,7 +35,7 @@ class update_referint(PreUpdate): entry = ldap.get_entry(self.referint_dn) except errors.NotFound: root_logger.error("Referential integrity configuration not found") - return False, False, [] + return False, [] referint_membership_attrs = [] @@ -49,7 +49,7 @@ class update_referint(PreUpdate): entry['nsslapd-pluginArg0'] = None else: root_logger.info("Plugin already uses new style, skipping") - return False, False, [] + return False, [] # nsslapd-pluginArg1 -> referint-logfile logfile = entry.get('nsslapd-pluginArg1') @@ -83,8 +83,8 @@ class update_referint(PreUpdate): ldap.update_entry(entry) except errors.EmptyModlist: root_logger.debug("No modifications required") - return False, False, [] + return False, [] - return False, True, [] + return False, [] api.register(update_referint) diff --git a/ipaserver/install/plugins/update_services.py b/ipaserver/install/plugins/update_services.py index 2122abb10a14824ea752123cb59bea8ce9a7d665..1de856885de9ae0fb628b573cd3d8197539eb4cb 100644 --- a/ipaserver/install/plugins/update_services.py +++ b/ipaserver/install/plugins/update_services.py @@ -51,16 +51,16 @@ class update_service_principalalias(PostUpdate): except errors.NotFound: root_logger.debug("update_service_principalalias: no service " "to update found") - return (False, False, []) + return False, [] except errors.ExecutionError, e: root_logger.error("update_service_principalalias: cannot " "retrieve list of affected services: %s", e) - return (False, False, []) + return False, [] if not entries: # no entry was returned, rather break than continue cycling root_logger.debug("update_service_principalalias: no service " "was returned") - return (False, False, []) + return False, [] root_logger.debug("update_service_principalalias: found %d " "services to update, truncated: %s", len(entries), truncated) @@ -83,12 +83,12 @@ class update_service_principalalias(PostUpdate): # exit loop to avoid infinite cycles root_logger.error("update_service_principalalias: error(s)" "detected during service update") - return (False, False, []) + return False, [] elif not truncated: # all affected entries updated, exit the loop root_logger.debug("update_service_principalalias: all affected" " services updated") - return (False, False, []) - return (False, False, []) + return False, [] + return False, [] api.register(update_service_principalalias) diff --git a/ipaserver/install/plugins/update_uniqueness.py b/ipaserver/install/plugins/update_uniqueness.py index e0ee150a7337a052731a0ed26eb64a4a8c01fb90..fa6b990e09b36159fe3141875a2be7e95e9690f1 100644 --- a/ipaserver/install/plugins/update_uniqueness.py +++ b/ipaserver/install/plugins/update_uniqueness.py @@ -184,7 +184,7 @@ class update_uniqueness_plugins_to_new_syntax(PreUpdate): except errors.NotFound: root_logger.debug("No uniqueness plugin entries with old style " "configuration found") - return False, False, [] + return False, [] update_list = [] new_attributes = [ @@ -220,6 +220,6 @@ class update_uniqueness_plugins_to_new_syntax(PreUpdate): update_list.append(update) - return False, True, update_list + return False, update_list api.register(update_uniqueness_plugins_to_new_syntax) diff --git a/ipaserver/install/plugins/updateclient.py b/ipaserver/install/plugins/updateclient.py index 1c0fd5071dbef34876c0366d3de07207844336c7..357ca3bc87905007e91c301eb6505ddb5167639d 100644 --- a/ipaserver/install/plugins/updateclient.py +++ b/ipaserver/install/plugins/updateclient.py @@ -32,13 +32,9 @@ class updateclient(backend.Executioner): An update plugin can be executed before the file-based plugins or afterward. Each plugin returns three values: - 1. restart: dirsrv needs to be restarted BEFORE this update is + 1. restart: dirsrv will be restarted AFTER this update is applied. - 2. apply_now: when True the update is applied when the plugin - returns. Otherwise the update is cached until all - plugins of that update type are complete, then they - are applied together. - 3. updates: A list of updates to be applied. + 2. updates: A list of updates to be applied. updates is a dictionary keyed on dn. The value of an update is a dictionary with the following possible values: @@ -120,18 +116,15 @@ class updateclient(backend.Executioner): result = [] ld = LDAPUpdate(dm_password=dm_password, sub_dict={}, ldapi=ldapi) for update in self.order(updatetype): - (restart, apply_now, res) = self.run(update.name, **kw) + 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) - if apply_now: - ld.update_from_dict(res) - elif res: - result.extend(res) - self.destroy_context() return result diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py index 4d5ce52d4073660fc0c1c1ba09e993b250e11fcb..c9c3c9f9c2dfd72add747539aa58211d72dfe895 100644 --- a/ipaserver/install/plugins/upload_cacrt.py +++ b/ipaserver/install/plugins/upload_cacrt.py @@ -93,6 +93,6 @@ class update_upload_cacrt(PostUpdate): entry.single_value['cACertificate;binary'] = ca_cert ldap.update_entry(entry) - return (False, False, []) + return False, [] api.register(update_upload_cacrt) -- 2.1.0
From 5a9466b1f16249d471d9479bcc86052692e5e0e3 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Wed, 18 Mar 2015 15:46:00 +0100 Subject: [PATCH 4/9] 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 --- install/tools/man/ipa-ldap-updater.1 | 11 +- install/updates/05-pre_upgrade_plugins.update | 10 ++ install/updates/90-post_upgrade_plugins.update | 20 +++ install/updates/Makefile.am | 2 + ipalib/frontend.py | 6 +- ipaserver/install/dsinstance.py | 3 +- ipaserver/install/ipa_ldap_updater.py | 11 +- ipaserver/install/ldapupdate.py | 184 ++++++++++++++++----- ipaserver/install/plugins/__init__.py | 6 - ipaserver/install/plugins/adtrust.py | 13 +- ipaserver/install/plugins/baseupdate.py | 32 +--- ipaserver/install/plugins/ca_renewal_master.py | 6 +- ipaserver/install/plugins/dns.py | 19 +-- .../install/plugins/fix_replica_agreements.py | 7 +- ipaserver/install/plugins/rename_managed.py | 11 +- ipaserver/install/plugins/update_idranges.py | 15 +- .../install/plugins/update_managed_permissions.py | 9 +- ipaserver/install/plugins/update_pacs.py | 9 +- ipaserver/install/plugins/update_passsync.py | 14 +- ipaserver/install/plugins/update_referint.py | 9 +- ipaserver/install/plugins/update_services.py | 8 +- ipaserver/install/plugins/update_uniqueness.py | 7 +- ipaserver/install/plugins/updateclient.py | 147 ---------------- ipaserver/install/plugins/upload_cacrt.py | 8 +- ipaserver/install/upgradeinstance.py | 2 +- 25 files changed, 235 insertions(+), 334 deletions(-) create mode 100644 install/updates/05-pre_upgrade_plugins.update create mode 100644 install/updates/90-post_upgrade_plugins.update delete mode 100644 ipaserver/install/plugins/updateclient.py diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1 index 83da26d5da70551c23ea636184e1b2ce98d374c2..ce272ea26ccd746ff85b464ecc8a7b8e46595a29 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 0000000000000000000000000000000000000000..d0e3eb7cedca3232209b1d8ae1f17da2cfbcc83f --- /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 0000000000000000000000000000000000000000..8e8fe09414eac57d2e8c15dcfc4aed64b6e35cd5 --- /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 40de5635621071d34b6475d51ca598ed41a8ba09..0d63d9ea8d85f1add5f036e7a39f89543586d33b 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 36d9ab2d47ee453db8853b8343b3c7193e783fcb..19190c37878fc50f70113e10b4af0bdd7183f2a1 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 52382873527502b28943f32b2e14990dee69f424..8a76e773f0a464529331d9e2e459c9cc5ea0522e 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 473af961b6f98736d189bdc30ddf70afda922659..c9362ca6dc6e31bfcb1e0ba296bf82d175dd581a 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 d3e3c3c325fc9c88f48330999111450a6fe688a3..e0b7b094f0e4a5077f33937b31931eeb2f2fd00b 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. + + updates is a dictionary keyed on dn. 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 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 49bef4df80d9b8ea2f5861dcb69c7ae2fb882472..6e76841ce2588416f2cb9986ac3bd5fe4e515892 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 3ad75135ddb1e3ef253563446d7cf4185cf12484..7a4f543f5446aec88a168b766e0cd45b6995f8f8 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 fa997c9dbe933be28fe462923a84cce338e05b6c..d39d8ac89618a1d65af13c72aa1627894d6c0272 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 3cd1ad240413f84ab4217d282949b930b577dc05..afbf8129cd88b6fb4d684df90e075a6fd670e1c4 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 082c066d0f270242ffa4844a51ec82272e31b5e9..67c08ccb4a956f34ffaefa1beb43b41c2e370a5e 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 98ed9e6379179a89e68ba8153b6ba27e389efd38..0b1db1c603a45bda74293d22716d698c5b008fe3 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 d3c5bf249e04a09ef9111f21a66becf5f95c2a8d..1c031543c07280a09984b66875a21ce8ed4fb840 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 ff061bef702e77ae3be21e9614262d970e234f1f..a6f2527cc441290cb18dc8885776cfd8dca2ca9e 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 e98523f442c1ae7b87ca92ba7e7846859da15087..9ca3eac6c533cac7f7ceb428494a91e7e57ee245 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 ffe6c667015423d4c465f2a3e9778ab99fbf8432..5f8eec2c8b4d3768bffb67876a5ccce5ced649a9 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 61c3a77c532bb8e56e5c6bec611058df96bf2338..1bda790fc422f32e5755be5ec9933ac358ec53f0 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 aa3a4a3fa3e98abb23d74f9be0354a5cbad38d7e..960a5ad1a8fe13d985671e69c6355ac35beee0f1 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 1de856885de9ae0fb628b573cd3d8197539eb4cb..490d0748b3fa26be249588029a9079fb29aa9bb5 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 fa6b990e09b36159fe3141875a2be7e95e9690f1..53cab6d31335bc523d7338e920057fce2e56d347 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 357ca3bc87905007e91c301eb6505ddb5167639d..0000000000000000000000000000000000000000 --- a/ipaserver/install/plugins/updateclient.py +++ /dev/null @@ -1,147 +0,0 @@ -# Authors: Rob Crittenden <rcrit...@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. - - updates is a dictionary keyed on dn. 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 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 c9c3c9f9c2dfd72add747539aa58211d72dfe895..db34e1cb74d91b74d55199b9b59ddea9c8f9bc18 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 2f9039dd7f6b37e89deb02a2a6856a61ec32f51c..160b735c8f567779dcb5d94cc6ae840338b9eef1 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) -- 2.1.0
From 99a3cb15d9b94cb0a1170b811aa88284dd30f161 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Thu, 19 Mar 2015 15:32:21 +0100 Subject: [PATCH 5/9] Server Upgrade: plugins should use ldapupdater API instance This is required to have proper LDAP connection in plugins https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/plugins/adtrust.py | 17 ++++++++------- ipaserver/install/plugins/dns.py | 25 +++++++++++----------- .../install/plugins/fix_replica_agreements.py | 6 ++++-- ipaserver/install/plugins/rename_managed.py | 2 +- ipaserver/install/plugins/update_idranges.py | 4 ++-- ipaserver/install/plugins/update_pacs.py | 2 +- ipaserver/install/plugins/update_passsync.py | 2 +- ipaserver/install/plugins/update_services.py | 2 +- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py index 7a4f543f5446aec88a168b766e0cd45b6995f8f8..287595d96552b5a3a71ac033e0ceacea3ed8d4a8 100644 --- a/ipaserver/install/plugins/adtrust.py +++ b/ipaserver/install/plugins/adtrust.py @@ -32,7 +32,7 @@ class update_default_range(Updater): def execute(self, **options): ldap = self.api.Backend.ldap2 - dn = DN(api.env.container_ranges, api.env.basedn) + dn = DN(self.api.env.container_ranges, self.api.env.basedn) search_filter = "objectclass=ipaDomainIDRange" try: (entries, truncated) = ldap.find_entries(search_filter, [], dn) @@ -42,7 +42,8 @@ class update_default_range(Updater): root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin") return False, [] - dn = DN(('cn', 'admins'), api.env.container_group, api.env.basedn) + dn = DN(('cn', 'admins'), self.api.env.container_group, + self.api.env.basedn) try: admins_entry = ldap.get_entry(dn, ['gidnumber']) except errors.NotFound: @@ -51,7 +52,7 @@ class update_default_range(Updater): return False, [] id_range_base_id = admins_entry['gidnumber'][0] - id_range_name = '%s_id_range' % api.env.realm + id_range_name = '%s_id_range' % self.api.env.realm id_range_size = DEFAULT_ID_RANGE_SIZE range_entry = ['objectclass:top', @@ -63,8 +64,8 @@ class update_default_range(Updater): 'iparangetype:ipa-local', ] - dn = DN(('cn', '%s_id_range' % api.env.realm), - api.env.container_ranges, api.env.basedn) + dn = DN(('cn', '%s_id_range' % self.api.env.realm), + self.api.env.container_ranges, self.api.env.basedn) update = {'dn': dn, 'default': range_entry} @@ -74,7 +75,7 @@ class update_default_range(Updater): # bigger range (option --idmax). # We should make our best to check if this is the case and provide # user with an information how to fix it. - dn = DN(api.env.container_dna_posix_ids, api.env.basedn) + dn = DN(self.api.env.container_dna_posix_ids, self.api.env.basedn) search_filter = "objectclass=dnaSharedConfig" attrs = ['dnaHostname', 'dnaRemainingValues'] try: @@ -124,8 +125,8 @@ class update_default_trust_view(Updater): ldap = self.api.Backend.ldap2 default_trust_view_dn = DN(('cn', 'Default Trust View'), - api.env.container_views, - api.env.basedn) + self.api.env.container_views, + self.api.env.basedn) default_trust_view_entry = [ 'objectclass:top', diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py index 67c08ccb4a956f34ffaefa1beb43b41c2e370a5e..95c004d21bfc91d4a3e8035d6a68d12c5fbac0a0 100644 --- a/ipaserver/install/plugins/dns.py +++ b/ipaserver/install/plugins/dns.py @@ -62,7 +62,7 @@ class update_dnszones(Updater): return False, [] try: - zones = api.Command.dnszone_find(all=True)['result'] + zones = self.api.Command.dnszone_find(all=True)['result'] except errors.NotFound: self.log.info('No DNS zone to update found') return False, [] @@ -77,14 +77,15 @@ class update_dnszones(Updater): # do not open zone transfers by default update['idnsallowtransfer'] = u'none;' - old_policy = util.get_dns_forward_zone_update_policy(api.env.realm, ('A', 'AAAA')) + old_policy = util.get_dns_forward_zone_update_policy( + self.api.env.realm, ('A', 'AAAA')) if zone.get('idnsupdatepolicy', [''])[0] == old_policy: update['idnsupdatepolicy'] = util.get_dns_forward_zone_update_policy(\ - api.env.realm) + self.api.env.realm) if update: # FIXME: https://fedorahosted.org/freeipa/ticket/4722 - api.Command.dnszone_mod(zone[u'idnsname'][0].make_absolute(), + self.api.Command.dnszone_mod(zone[u'idnsname'][0].make_absolute(), **update) return False, [] @@ -156,7 +157,7 @@ class update_master_to_dnsforwardzones(Updater): def execute(self, **options): ldap = self.api.Backend.ldap2 # check LDAP if forwardzones already uses new semantics - dns_container_dn = DN(api.env.container_dns, api.env.basedn) + dns_container_dn = DN(self.api.env.container_dns, self.api.env.basedn) try: container_entry = ldap.get_entry(dns_container_dn) except errors.NotFound: @@ -181,7 +182,7 @@ class update_master_to_dnsforwardzones(Updater): # should detect if update in past has been executed, and set proper # DNSVersion into LDAP try: - fwzones = api.Command.dnsforwardzone_find()['result'] + fwzones = self.api.Command.dnsforwardzone_find()['result'] except errors.NotFound: # No forwardzones found, update probably has not been executed yet pass @@ -193,7 +194,7 @@ class update_master_to_dnsforwardzones(Updater): zones = [] try: # raw values are required to store into ldif - zones = api.Command.dnszone_find(all=True, + zones = self.api.Command.dnszone_find(all=True, raw=True, sizelimit=0)['result'] except errors.NotFound: @@ -249,7 +250,7 @@ class update_master_to_dnsforwardzones(Updater): zone_to_privileges[zone['idnsname'][0]] = entry['member'] # raw values are required to store into ldif - records = api.Command['dnsrecord_find']( + records = self.api.Command['dnsrecord_find']( zone['idnsname'][0], all=True, raw=True, @@ -288,7 +289,7 @@ class update_master_to_dnsforwardzones(Updater): for zone in zones_to_transform: # delete master zone try: - api.Command['dnszone_del'](zone['idnsname']) + self.api.Command['dnszone_del'](zone['idnsname']) except Exception, e: self.log.error('Transform to forwardzone terminated: ' 'removing zone %s failed (%s)' % ( @@ -303,7 +304,7 @@ class update_master_to_dnsforwardzones(Updater): 'idnsforwarders': zone.get('idnsforwarders', []), 'idnsforwardpolicy': zone.get('idnsforwardpolicy', [u'first'])[0] } - api.Command['dnsforwardzone_add'](zone['idnsname'][0], **kw) + self.api.Command['dnsforwardzone_add'](zone['idnsname'][0], **kw) except Exception, e: self.log.error('Transform to forwardzone terminated: creating ' 'forwardzone %s failed' % @@ -314,7 +315,7 @@ class update_master_to_dnsforwardzones(Updater): # create permission if original zone has one if 'managedBy' in zone: try: - perm_name = api.Command['dnsforwardzone_add_permission']( + perm_name = self.api.Command['dnsforwardzone_add_permission']( zone['idnsname'][0])['value'] except Exception, e: self.log.error('Transform to forwardzone terminated: ' @@ -332,7 +333,7 @@ class update_master_to_dnsforwardzones(Updater): dn[0].value for dn in zone_to_privileges[zone['idnsname'][0]] ] try: - api.Command['permission_add_member'](perm_name, + self.api.Command['permission_add_member'](perm_name, privilege=privileges) except Exception, e: self.log.error('Unable to restore privileges for ' diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py index 0b1db1c603a45bda74293d22716d698c5b008fe3..413bf877d105ea96ce6522b65d7176d6cf85f6fd 100644 --- a/ipaserver/install/plugins/fix_replica_agreements.py +++ b/ipaserver/install/plugins/fix_replica_agreements.py @@ -37,10 +37,12 @@ class update_replica_attribute_lists(Updater): def execute(self, **options): # We need an IPAdmin connection to the backend self.log.debug("Start replication agreement exclude list update task") - conn = ipaldap.IPAdmin(api.env.host, ldapi=True, realm=api.env.realm) + conn = ipaldap.IPAdmin(self.api.env.host, ldapi=True, + realm=self.api.env.realm) conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name) - repl = replication.ReplicationManager(api.env.realm, api.env.host, + repl = replication.ReplicationManager(self.api.env.realm, + self.api.env.host, None, conn=conn) # We need to update only IPA replica agreements, not winsync diff --git a/ipaserver/install/plugins/rename_managed.py b/ipaserver/install/plugins/rename_managed.py index 1c031543c07280a09984b66875a21ce8ed4fb840..02f91e73b9b50f635eb8fccd12d11348b081dc58 100644 --- a/ipaserver/install/plugins/rename_managed.py +++ b/ipaserver/install/plugins/rename_managed.py @@ -48,7 +48,7 @@ class GenerateUpdateMixin(object): """ ldap = self.api.Backend.ldap2 - suffix = ipautil.realm_to_suffix(api.env.realm) + suffix = ipautil.realm_to_suffix(self.api.env.realm) searchfilter = '(objectclass=*)' definitions_managed_entries = [] diff --git a/ipaserver/install/plugins/update_idranges.py b/ipaserver/install/plugins/update_idranges.py index a6f2527cc441290cb18dc8885776cfd8dca2ca9e..3181e9ec54f19859c5bcbcde9ea551476d1910f7 100644 --- a/ipaserver/install/plugins/update_idranges.py +++ b/ipaserver/install/plugins/update_idranges.py @@ -32,7 +32,7 @@ class update_idrange_type(Updater): def execute(self, **options): ldap = self.api.Backend.ldap2 - base_dn = DN(api.env.container_ranges, api.env.basedn) + base_dn = DN(self.api.env.container_ranges, self.api.env.basedn) search_filter = ("(&(objectClass=ipaIDrange)(!(ipaRangeType=*)))") root_logger.debug("update_idrange_type: search for ID ranges with no " "type set") @@ -118,7 +118,7 @@ class update_idrange_baserid(Updater): def execute(self, **options): ldap = self.api.Backend.ldap2 - base_dn = DN(api.env.container_ranges, api.env.basedn) + base_dn = DN(self.api.env.container_ranges, self.api.env.basedn) search_filter = ("(&(objectClass=ipaTrustedADDomainRange)" "(ipaRangeType=ipa-ad-trust-posix)" "(!(ipaBaseRID=0)))") diff --git a/ipaserver/install/plugins/update_pacs.py b/ipaserver/install/plugins/update_pacs.py index 5f8eec2c8b4d3768bffb67876a5ccce5ced649a9..e361844e5eb91a045fe4edf38234ee688934603a 100644 --- a/ipaserver/install/plugins/update_pacs.py +++ b/ipaserver/install/plugins/update_pacs.py @@ -31,7 +31,7 @@ class update_pacs(Updater): ldap = self.api.Backend.ldap2 try: - dn = DN('cn=ipaConfig', 'cn=etc', api.env.basedn) + dn = DN('cn=ipaConfig', 'cn=etc', self.api.env.basedn) entry = ldap.get_entry(dn, ['ipakrbauthzdata']) pacs = entry.get('ipakrbauthzdata', []) except errors.NotFound: diff --git a/ipaserver/install/plugins/update_passsync.py b/ipaserver/install/plugins/update_passsync.py index 1bda790fc422f32e5755be5ec9933ac358ec53f0..a35f64ef46064725ee5460cfe2506f8ccbaf7955 100644 --- a/ipaserver/install/plugins/update_passsync.py +++ b/ipaserver/install/plugins/update_passsync.py @@ -50,7 +50,7 @@ class update_passync_privilege_update(Updater): root_logger.debug("Add PassSync user as a member of PassSync privilege") ldap = self.api.Backend.ldap2 passsync_dn = DN(('uid','passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'), - api.env.basedn) + self.api.env.basedn) passsync_privilege_dn = DN(('cn','PassSync Service'), self.api.env.container_privilege, self.api.env.basedn) diff --git a/ipaserver/install/plugins/update_services.py b/ipaserver/install/plugins/update_services.py index 490d0748b3fa26be249588029a9079fb29aa9bb5..975480d7bac01bd0024e056990f859fac996820b 100644 --- a/ipaserver/install/plugins/update_services.py +++ b/ipaserver/install/plugins/update_services.py @@ -33,7 +33,7 @@ class update_service_principalalias(Updater): def execute(self, **options): ldap = self.api.Backend.ldap2 - base_dn = DN(api.env.container_service, api.env.basedn) + base_dn = DN(self.api.env.container_service, self.api.env.basedn) search_filter = ("(&(objectclass=krbprincipal)(objectclass=ipaservice)" "(!(objectclass=ipakrbprincipal)))") root_logger.debug("update_service_principalalias: search for affected " -- 2.1.0
From adfc0616c2ba516b187040c87980d86ff4187d3b Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Mon, 23 Mar 2015 12:33:30 +0100 Subject: [PATCH 6/9] Server Upgrade: Handle connection better in updates_from_dict Connection should be closed if update is done https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/ldapupdate.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index e0b7b094f0e4a5077f33937b31931eeb2f2fd00b..9c88ee7252c860946c43a8f0713bb0e7fe7bbc7a 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -868,10 +868,11 @@ class LDAPUpdate: updates is a dictionary containing the updates """ self.modified = False - if not self.conn: + try: self.create_connection() - - self._run_updates(updates) + self._run_updates(updates) + finally: + self.close_connection() return self.modified -- 2.1.0
From c24087be2101e89aeb5b0219769adcd2aa8dc82d Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Mon, 23 Mar 2015 12:59:16 +0100 Subject: [PATCH 7/9] Server Upgrade: use ldap2 connection in fix_replica_agreements https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/plugins/fix_replica_agreements.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py index 413bf877d105ea96ce6522b65d7176d6cf85f6fd..a2aa4bce47988d06b192e78332742121d4ada060 100644 --- a/ipaserver/install/plugins/fix_replica_agreements.py +++ b/ipaserver/install/plugins/fix_replica_agreements.py @@ -37,9 +37,7 @@ class update_replica_attribute_lists(Updater): def execute(self, **options): # We need an IPAdmin connection to the backend self.log.debug("Start replication agreement exclude list update task") - conn = ipaldap.IPAdmin(self.api.env.host, ldapi=True, - realm=self.api.env.realm) - conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name) + conn = self.api.Backend.ldap2 repl = replication.ReplicationManager(self.api.env.realm, self.api.env.host, -- 2.1.0
From 50674ec3690b826788d75db0cb7eb33b1bc218a6 Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Mon, 23 Mar 2015 13:00:49 +0100 Subject: [PATCH 8/9] Server Upgrade: restart DS using ipaplatfom service Removes extra class DSRestart which do the same thing https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/ldapupdate.py | 8 +++--- ipaserver/install/plugins/baseupdate.py | 47 --------------------------------- 2 files changed, 4 insertions(+), 51 deletions(-) delete mode 100644 ipaserver/install/plugins/baseupdate.py diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 9c88ee7252c860946c43a8f0713bb0e7fe7bbc7a..1780362a0cfab52cfacb49a2373e21b8e2dc4589 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -36,11 +36,11 @@ 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, create_api from ipaplatform.paths import paths +from ipaplatform import services from ipapython.dn import DN from ipapython.ipa_log_manager import * from ipapython.ipautil import wait_for_open_socket @@ -883,7 +883,7 @@ class LDAPUpdate: self.conn = None def restart_ds(self): - dsrestart = DSRestart() - - dsrestart.create_instance() + dirsrv = services.knownservices.dirsrv + self.log.info('Restarting directory server to apply updates') + dirsrv.restart() wait_for_open_socket(self.socket_name) diff --git a/ipaserver/install/plugins/baseupdate.py b/ipaserver/install/plugins/baseupdate.py deleted file mode 100644 index d39d8ac89618a1d65af13c72aa1627894d6c0272..0000000000000000000000000000000000000000 --- a/ipaserver/install/plugins/baseupdate.py +++ /dev/null @@ -1,47 +0,0 @@ -# Authors: -# Rob Crittenden <rcrit...@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 ipalib import api -from ipalib import Object -from ipaserver.install import service - -class DSRestart(service.Service): - """ - Restart the 389-ds service. - """ - def __init__(self): - """ - This class is present to provide ldapupdate the means to - restart 389-ds. - """ - service.Service.__init__(self, "dirsrv") - - def start(self, instance_name="", capture_output=True, wait=True): - """ - During upgrades the server is listening only on the socket so - we don't want to wait on ports. The caller is responsible for - waiting for the socket to be ready. - """ - super(DSRestart, self).start(wait=False) - - def create_instance(self): - self.step("stopping directory server", self.stop) - self.step("starting directory server", self.start) - self.start_creation(start_message="Restarting Directory server " - "to apply updates", show_service_name=False) -- 2.1.0
From b6e5dd4b35f3fa1347b409ae8e733ad9d2ec82cd Mon Sep 17 00:00:00 2001 From: Martin Basti <mba...@redhat.com> Date: Mon, 23 Mar 2015 13:28:25 +0100 Subject: [PATCH 9/9] Server Upgrade: only root can run updates https://fedorahosted.org/freeipa/ticket/4904 --- ipaserver/install/ipa_ldap_updater.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index c9362ca6dc6e31bfcb1e0ba296bf82d175dd581a..b435a4dad8314eed3bbf1f65ceaeb43c57bff61f 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -67,6 +67,9 @@ class LDAPUpdater(admintool.AdminTool): options = self.options super(LDAPUpdater, self).validate_options(**kwargs) + if os.getegid() != 0: + raise admintool.ScriptError('Must be root to do an upgrade.', 1) + self.files = self.args for filename in self.files: @@ -105,12 +108,6 @@ class LDAPUpdater(admintool.AdminTool): class LDAPUpdater_Upgrade(LDAPUpdater): log_file_name = paths.IPAUPGRADE_LOG - def validate_options(self): - if os.getegid() != 0: - raise admintool.ScriptError('Must be root to do an upgrade.', 1) - - super(LDAPUpdater_Upgrade, self).validate_options(needs_root=True) - def run(self): super(LDAPUpdater_Upgrade, self).run() options = self.options @@ -134,18 +131,6 @@ class LDAPUpdater_Upgrade(LDAPUpdater): class LDAPUpdater_NonUpgrade(LDAPUpdater): log_file_name = paths.IPAUPGRADE_LOG - def validate_options(self): - super(LDAPUpdater_NonUpgrade, self).validate_options() - - # Need root for running plugins - if os.getegid() != 0: - if self.run_plugins: - raise admintool.ScriptError( - 'Plugins can only be run as root.', 1) - else: - # Can't log to the default file as non-root - self.log_file_name = None - def run(self): super(LDAPUpdater_NonUpgrade, self).run() options = self.options -- 2.1.0
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code