From 9005b9bc8aac7c1381aadb7d17107ebbebae005d Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 1 Mar 2013 15:02:14 -0500 Subject: Extend ipa-replica-manage to be able to manage DNA ranges. Attempt to automatically save DNA ranges when a master is removed. This is done by trying to find a master that does not yet define a DNA on-deck range. If one can be found then the range on the deleted master is added. If one cannot be found then it is reported as an error. Some validation of the ranges are done to ensure that they do overlap an IPA local range and do not overlap existing DNA ranges configured on other masters. http://freeipa.org/page/V3/Recover_DNA_Ranges https://fedorahosted.org/freeipa/ticket/3321 --- ipaserver/install/dsinstance.py | 3 +- ipaserver/install/replication.py | 98 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) (limited to 'ipaserver/install') diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 23843d75..c744c9ca 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -218,6 +218,7 @@ class DsInstance(service.Service): self.step("adding master entry", self.__add_master_entry) self.step("configuring Posix uid/gid generation", self.__config_uidgid_gen) + self.step("adding replication acis", self.__add_replication_acis) self.step("enabling compatibility plugin", self.__enable_compat_plugin) self.step("tuning directory server", self.__tuning) @@ -253,7 +254,6 @@ class DsInstance(service.Service): self.step("adding default layout", self.__add_default_layout) self.step("adding delegation layout", self.__add_delegation_layout) - self.step("adding replication acis", self.__add_replication_acis) self.step("creating container for managed entries", self.__managed_entries) self.step("configuring user private groups", self.__user_private_groups) self.step("configuring netgroups from hostgroups", self.__host_nis_groups) @@ -284,7 +284,6 @@ class DsInstance(service.Service): self.__common_setup(True) self.step("setting up initial replication", self.__setup_replica) - self.step("adding replication acis", self.__add_replication_acis) # See LDIFs for automember configuration during replica install self.step("setting Auto Member configuration", self.__add_replica_automember_config) self.step("enabling S4U2Proxy delegation", self.__setup_s4u2proxy) diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index 076d4f87..c1ca0aaa 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -37,6 +37,7 @@ IPA_USER_CONTAINER = DN(('cn', 'users'), ('cn', 'accounts')) PORT = 636 TIMEOUT = 120 REPL_MAN_DN = DN(('cn', 'replication manager'), ('cn', 'config')) +DNA_DN = DN(('cn', 'Posix IDs'), ('cn', 'Distributed Numeric Assignment Plugin'), ('cn', 'plugins'), ('cn', 'config')) IPA_REPLICA = 1 WINSYNC = 2 @@ -1307,3 +1308,100 @@ class ReplicationManager(object): print "This may be safely interrupted with Ctrl+C" wait_for_task(self.conn, dn) + + def get_DNA_range(self, hostname): + """ + Return the DNA range on this server as a tuple, (next, max), or + (None, None) if no range has been assigned yet. + + Raises an exception on errors reading an entry. + """ + entry = self.conn.get_entry(DNA_DN) + + nextvalue = int(entry.single_value("dnaNextValue", 0)) + maxvalue = int(entry.single_value("dnaMaxValue", 0)) + + sharedcfgdn = entry.single_value("dnaSharedCfgDN", None) + if sharedcfgdn is not None: + sharedcfgdn = DN(sharedcfgdn) + + shared_entry = self.conn.get_entry(sharedcfgdn) + remaining = int(shared_entry.single_value("dnaRemainingValues", 0)) + else: + remaining = 0 + + if nextvalue == 0 and maxvalue == 0: + return (None, None) + + # Check the magic values for an unconfigured DNA entry + if maxvalue == 1100 and nextvalue == 1101 and remaining == 0: + return (None, None) + else: + return (nextvalue, maxvalue) + + def get_DNA_next_range(self, hostname): + """ + Return the DNA "on-deck" range on this server as a tuple, (next, max), + or + (None, None) if no range has been assigned yet. + + Raises an exception on errors reading an entry. + """ + entry = self.conn.get_entry(DNA_DN) + + range = entry.single_value("dnaNextRange", None) + + if range is None: + return (None, None) + + try: + (next, max) = range.split('-') + except ValueError: + # Should not happen, malformed entry, return nothing. + return (None, None) + + return (int(next), int(max)) + + def save_DNA_next_range(self, next_start, next_max): + """ + Save a DNA range into the on-deck value. + + This adds a dnaNextRange value to the DNA configuration. This + attribute takes the form of start-next. + + Returns True on success. + Returns False if the range is already defined. + Raises an exception on failure. + """ + entry = self.conn.get_entry(DNA_DN) + + range = entry.single_value("dnaNextRange", None) + + if range is not None and next_start != 0 and next_max != 0: + return False + + if next_start == 0 and next_max == 0: + entry["dnaNextRange"] = None + else: + entry["dnaNextRange"] = "%s-%s" % (next_start, next_max) + + self.conn.update_entry(entry) + + return True + + def save_DNA_range(self, next_start, next_max): + """ + Save a DNA range. + + This is potentially very dangerous. + + Returns True on success. Raises an exception on failure. + """ + entry = self.conn.get_entry(DNA_DN) + + entry["dnaNextValue"] = next_start + entry["dnaMaxValue"] = next_max + + self.conn.update_entry(entry) + + return True -- cgit