diff options
Diffstat (limited to 'source4/scripting')
-rw-r--r-- | source4/scripting/python/samba/kcc_utils.py | 460 |
1 files changed, 214 insertions, 246 deletions
diff --git a/source4/scripting/python/samba/kcc_utils.py b/source4/scripting/python/samba/kcc_utils.py index 13bc2412d6..f762f4a252 100644 --- a/source4/scripting/python/samba/kcc_utils.py +++ b/source4/scripting/python/samba/kcc_utils.py @@ -3,6 +3,7 @@ # KCC topology utilities # # Copyright (C) Dave Craft 2011 +# Copyright (C) Jelmer Vernooij 2011 # # 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 @@ -17,37 +18,41 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import samba, ldb +import ldb import uuid -from samba import dsdb -from samba.dcerpc import misc -from samba.dcerpc import drsblobs -from samba.dcerpc import drsuapi -from samba.common import dsdb_Dn -from samba.ndr import ndr_unpack -from samba.ndr import ndr_pack +from samba import dsdb +from samba.dcerpc import ( + drsblobs, + drsuapi, + misc, + ) +from samba.common import dsdb_Dn +from samba.ndr import (ndr_unpack, ndr_pack) -class NCType: + +class NCType(object): (unknown, schema, domain, config, application) = range(0, 5) -class NamingContext: - """Base class for a naming context. Holds the DN, - GUID, SID (if available) and type of the DN. - Subclasses may inherit from this and specialize + +class NamingContext(object): + """Base class for a naming context. + + Holds the DN, GUID, SID (if available) and type of the DN. + Subclasses may inherit from this and specialize """ def __init__(self, nc_dnstr, nc_guid=None, nc_sid=None): """Instantiate a NamingContext - :param nc_dnstr: NC dn string - :param nc_guid: NC guid - :param nc_sid: NC sid + + :param nc_dnstr: NC dn string + :param nc_guid: NC guid + :param nc_sid: NC sid """ - self.nc_dnstr = nc_dnstr - self.nc_guid = nc_guid - self.nc_sid = nc_sid - self.nc_type = NCType.unknown - return + self.nc_dnstr = nc_dnstr + self.nc_guid = nc_guid + self.nc_sid = nc_sid + self.nc_type = NCType.unknown def __str__(self): '''Debug dump string output of class''' @@ -56,7 +61,6 @@ class NamingContext: text = text + "\n\tnc_guid=%s" % str(self.nc_guid) text = text + "\n\tnc_sid=%s" % self.nc_sid text = text + "\n\tnc_type=%s" % self.nc_type - return text def is_schema(self): @@ -91,15 +95,15 @@ class NamingContext: self.nc_type = NCType.domain else: self.nc_type = NCType.application - return def identify_by_dsa_attr(self, samdb, attr): """Given an NC which has been discovered thru the - nTDSDSA database object, determine what type of NC - it is (i.e. schema, config, domain, application) via - the use of the schema attribute under which the NC - was found. - :param attr: attr of nTDSDSA object where NC DN appears + nTDSDSA database object, determine what type of NC + it is (i.e. schema, config, domain, application) via + the use of the schema attribute under which the NC + was found. + + :param attr: attr of nTDSDSA object where NC DN appears """ # If the NC is listed under msDS-HasDomainNCs then # this can only be a domain NC and it is our default @@ -124,29 +128,29 @@ class NamingContext: if self.nc_type == NCType.unknown: self.identify_by_basedn(samdb) - return class NCReplica(NamingContext): - """Class defines a naming context replica that is relative - to a specific DSA. This is a more specific form of - NamingContext class (inheriting from that class) and it - identifies unique attributes of the DSA's replica for a NC. + """Naming context replica that is relative to a specific DSA. + + This is a more specific form of NamingContext class (inheriting from that + class) and it identifies unique attributes of the DSA's replica for a NC. """ - def __init__(self, dsa_dnstr, dsa_guid, nc_dnstr, \ + def __init__(self, dsa_dnstr, dsa_guid, nc_dnstr, nc_guid=None, nc_sid=None): """Instantiate a Naming Context Replica - :param dsa_guid: GUID of DSA where replica appears - :param nc_dnstr: NC dn string - :param nc_guid: NC guid - :param nc_sid: NC sid + + :param dsa_guid: GUID of DSA where replica appears + :param nc_dnstr: NC dn string + :param nc_guid: NC guid + :param nc_sid: NC sid """ - self.rep_dsa_dnstr = dsa_dnstr - self.rep_dsa_guid = dsa_guid - self.rep_default = False # replica for DSA's default domain - self.rep_partial = False - self.rep_ro = False - self.rep_instantiated_flags = 0 + self.rep_dsa_dnstr = dsa_dnstr + self.rep_dsa_guid = dsa_guid + self.rep_default = False # replica for DSA's default domain + self.rep_partial = False + self.rep_ro = False + self.rep_instantiated_flags = 0 # RepsFromTo tuples self.rep_repsFrom = [] @@ -160,7 +164,6 @@ class NCReplica(NamingContext): # Call my super class we inherited from NamingContext.__init__(self, nc_dnstr, nc_guid, nc_sid) - return def __str__(self): '''Debug dump string output of class''' @@ -183,13 +186,13 @@ class NCReplica(NamingContext): self.rep_instantiated_flags = 0 else: self.rep_instantiated_flags = flags - return def identify_by_dsa_attr(self, samdb, attr): """Given an NC which has been discovered thru the - nTDSDSA database object, determine what type of NC - replica it is (i.e. partial, read only, default) - :param attr: attr of nTDSDSA object where NC DN appears + nTDSDSA database object, determine what type of NC + replica it is (i.e. partial, read only, default) + + :param attr: attr of nTDSDSA object where NC DN appears """ # If the NC was found under hasPartialReplicaNCs # then a partial replica at this dsa @@ -231,11 +234,9 @@ class NCReplica(NamingContext): # context type by calling the super class method # of the same name NamingContext.identify_by_dsa_attr(self, samdb, attr) - return def is_default(self): - """Returns True if this is a default domain NC for the dsa - that this NC appears on + """Whether this is a default domain for the dsa that this NC appears on """ return self.rep_default @@ -249,10 +250,10 @@ class NCReplica(NamingContext): def is_present(self): """Given an NC replica which has been discovered thru the - nTDSDSA database object and populated with replica flags - from the msDS-HasInstantiatedNCs; return whether the NC - replica is present (true) or if the IT_NC_GOING flag is - set then the NC replica is not present (false) + nTDSDSA database object and populated with replica flags + from the msDS-HasInstantiatedNCs; return whether the NC + replica is present (true) or if the IT_NC_GOING flag is + set then the NC replica is not present (false) """ if self.rep_present_criteria_one and \ self.rep_instantiated_flags & dsdb.INSTANCE_TYPE_NC_GOING == 0: @@ -261,28 +262,26 @@ class NCReplica(NamingContext): def load_repsFrom(self, samdb): """Given an NC replica which has been discovered thru the nTDSDSA - database object, load the repsFrom attribute for the local replica. - held by my dsa. The repsFrom attribute is not replicated so this - attribute is relative only to the local DSA that the samdb exists on + database object, load the repsFrom attribute for the local replica. + held by my dsa. The repsFrom attribute is not replicated so this + attribute is relative only to the local DSA that the samdb exists on """ try: res = samdb.search(base=self.nc_dnstr, scope=ldb.SCOPE_BASE, attrs=[ "repsFrom" ]) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find NC for (%s) - (%s)" % \ + raise Exception("Unable to find NC for (%s) - (%s)" % (self.nc_dnstr, estr)) - return msg = res[0] # Possibly no repsFrom if this is a singleton DC if "repsFrom" in msg: for value in msg["repsFrom"]: - rep = RepsFromTo(self.nc_dnstr, \ + rep = RepsFromTo(self.nc_dnstr, ndr_unpack(drsblobs.repsFromToBlob, value)) self.rep_repsFrom.append(rep) - return def commit_repsFrom(self, samdb): """Commit repsFrom to the database""" @@ -297,7 +296,7 @@ class NCReplica(NamingContext): # reflect the reference docs. As of right now this # commit to the database will work as its what the # older KCC also did - modify = False + modify = False newreps = [] for repsFrom in self.rep_repsFrom: @@ -318,7 +317,7 @@ class NCReplica(NamingContext): if modify == False: return - m = ldb.Message() + m = ldb.Message() m.dn = ldb.Dn(samdb, self.nc_dnstr) m["repsFrom"] = \ @@ -328,9 +327,8 @@ class NCReplica(NamingContext): samdb.modify(m) except ldb.LdbError, estr: - raise Exception("Could not set repsFrom for (%s) - (%s)" % \ + raise Exception("Could not set repsFrom for (%s) - (%s)" % (self.dsa_dnstr, estr)) - return def load_fsmo_roles(self, samdb): # XXX - to be implemented @@ -340,19 +338,22 @@ class NCReplica(NamingContext): # XXX - to be implemented return False -class DirectoryServiceAgent: + +class DirectoryServiceAgent(object): def __init__(self, dsa_dnstr): - """Initialize DSA class. Class is subsequently - fully populated by calling the load_dsa() method - :param dsa_dnstr: DN of the nTDSDSA + """Initialize DSA class. + + Class is subsequently fully populated by calling the load_dsa() method + + :param dsa_dnstr: DN of the nTDSDSA """ - self.dsa_dnstr = dsa_dnstr - self.dsa_guid = None - self.dsa_ivid = None - self.dsa_is_ro = False - self.dsa_options = 0 - self.dsa_behavior = 0 + self.dsa_dnstr = dsa_dnstr + self.dsa_guid = None + self.dsa_ivid = None + self.dsa_is_ro = False + self.dsa_options = 0 + self.dsa_behavior = 0 self.default_dnstr = None # default domain dn string for dsa # NCReplicas for this dsa that are "present" @@ -368,8 +369,6 @@ class DirectoryServiceAgent: # in the database. Indexed by DN string of connection self.connect_table = {} - return - def __str__(self): '''Debug dump string output of class''' @@ -407,19 +406,17 @@ class DirectoryServiceAgent: return False def is_minimum_behavior(self, version): - """Is dsa at minimum windows level greater than or - equal to (version) - :param version: Windows version to test against - (e.g. DS_BEHAVIOR_WIN2008) + """Is dsa at minimum windows level greater than or equal to (version) + + :param version: Windows version to test against + (e.g. DS_BEHAVIOR_WIN2008) """ if self.dsa_behavior >= version: return True return False def should_translate_ntdsconn(self): - """Returns True if DSA object allows NTDSConnection - translation in its options. False otherwise. - """ + """Whether this allows NTDSConnection translation in its options.""" if (self.options & dsdb.DS_NTDSDSA_OPT_DISABLE_NTDSCONN_XLATE) != 0: return False return True @@ -430,37 +427,33 @@ class DirectoryServiceAgent: return self.current_rep_table, self.needed_rep_table def get_parent_dnstr(self): - """Drop the leading portion of the DN string - (e.g. CN=NTDS Settings,) which will give us - the parent DN string of this object - """ + """Get the parent DN string of this object.""" head, sep, tail = self.dsa_dnstr.partition(',') return tail def load_dsa(self, samdb): - """Method to load a DSA from the samdb. Prior initialization - has given us the DN of the DSA that we are to load. This - method initializes all other attributes, including loading - the NC replica table for this DSA. - Raises an Exception on error. + """Load a DSA from the samdb. + + Prior initialization has given us the DN of the DSA that we are to + load. This method initializes all other attributes, including loading + the NC replica table for this DSA. """ controls = [ "extended_dn:1:1" ] - attrs = [ "objectGUID", - "invocationID", - "options", - "msDS-isRODC", - "msDS-Behavior-Version" ] + attrs = ["objectGUID", + "invocationID", + "options", + "msDS-isRODC", + "msDS-Behavior-Version"] try: res = samdb.search(base=self.dsa_dnstr, scope=ldb.SCOPE_BASE, attrs=attrs, controls=controls) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find nTDSDSA for (%s) - (%s)" % \ + raise Exception("Unable to find nTDSDSA for (%s) - (%s)" % (self.dsa_dnstr, estr)) - return msg = res[0] - self.dsa_guid = misc.GUID(samdb.schema_format_value("objectGUID", \ + self.dsa_guid = misc.GUID(samdb.schema_format_value("objectGUID", msg["objectGUID"][0])) # RODCs don't originate changes and thus have no invocationId, @@ -486,19 +479,17 @@ class DirectoryServiceAgent: # Load the nTDSConnection that are enumerated on this dsa self.load_connection_table(samdb) - return - - def load_current_replica_table(self, samdb): - """Method to load the NC replica's listed for DSA object. This - method queries the samdb for (hasMasterNCs, msDS-hasMasterNCs, - hasPartialReplicaNCs, msDS-HasDomainNCs, msDS-hasFullReplicaNCs, - and msDS-HasInstantiatedNCs) to determine complete list of - NC replicas that are enumerated for the DSA. Once a NC - replica is loaded it is identified (schema, config, etc) and - the other replica attributes (partial, ro, etc) are determined. - Raises an Exception on error. - :param samdb: database to query for DSA replica list + """Method to load the NC replica's listed for DSA object. + + This method queries the samdb for (hasMasterNCs, msDS-hasMasterNCs, + hasPartialReplicaNCs, msDS-HasDomainNCs, msDS-hasFullReplicaNCs, and + msDS-HasInstantiatedNCs) to determine complete list of NC replicas that + are enumerated for the DSA. Once a NC replica is loaded it is + identified (schema, config, etc) and the other replica attributes + (partial, ro, etc) are determined. + + :param samdb: database to query for DSA replica list """ controls = ["extended_dn:1:1"] ncattrs = [ # not RODC - default, config, schema (old style) @@ -518,9 +509,8 @@ class DirectoryServiceAgent: attrs=ncattrs, controls=controls) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find nTDSDSA NCs for (%s) - (%s)" % \ + raise Exception("Unable to find nTDSDSA NCs for (%s) - (%s)" % (self.dsa_dnstr, estr)) - return # The table of NCs for the dsa we are searching tmp_table = {} @@ -546,17 +536,16 @@ class DirectoryServiceAgent: # its methods to parse the extended pieces. # Note we don't really need the exact sid value # but instead only need to know if its present. - dsdn = dsdb_Dn(samdb, value) - guid = dsdn.dn.get_extended_component('GUID') - sid = dsdn.dn.get_extended_component('SID') + dsdn = dsdb_Dn(samdb, value) + guid = dsdn.dn.get_extended_component('GUID') + sid = dsdn.dn.get_extended_component('SID') flags = dsdn.get_binary_integer() dnstr = str(dsdn.dn) if guid is None: - raise Exception("Missing GUID for (%s) - (%s: %s)" % \ + raise Exception("Missing GUID for (%s) - (%s: %s)" % (self.dsa_dnstr, k, value)) - else: - guid = misc.GUID(guid) + guid = misc.GUID(guid) if not dnstr in tmp_table: rep = NCReplica(self.dsa_dnstr, self.dsa_guid, @@ -577,11 +566,9 @@ class DirectoryServiceAgent: self.default_dnstr = dnstr else: raise Exception("No nTDSDSA NCs for (%s)" % self.dsa_dnstr) - return # Assign our newly built NC replica table to this dsa self.current_rep_table = tmp_table - return def add_needed_replica(self, rep): """Method to add a NC replica that "should be present" to the @@ -590,12 +577,10 @@ class DirectoryServiceAgent: if not rep.nc_dnstr in self.needed_rep_table.keys(): self.needed_rep_table[rep.nc_dnstr] = rep - return - def load_connection_table(self, samdb): """Method to load the nTDSConnections listed for DSA object. - Raises an Exception on error. - :param samdb: database to query for DSA connection list + + :param samdb: database to query for DSA connection list """ try: res = samdb.search(base=self.dsa_dnstr, @@ -603,9 +588,8 @@ class DirectoryServiceAgent: expression="(objectClass=nTDSConnection)") except ldb.LdbError, (enum, estr): - raise Exception("Unable to find nTDSConnection for (%s) - (%s)" % \ + raise Exception("Unable to find nTDSConnection for (%s) - (%s)" % (self.dsa_dnstr, estr)) - return for msg in res: dnstr = str(msg.dn) @@ -618,7 +602,6 @@ class DirectoryServiceAgent: connect.load_connection(samdb) self.connect_table[dnstr] = connect - return def commit_connection_table(self, samdb): """Method to commit any uncommitted nTDSConnections @@ -631,7 +614,6 @@ class DirectoryServiceAgent: def add_connection(self, dnstr, connect): self.connect_table[dnstr] = connect - return def get_connection_by_from_dnstr(self, from_dnstr): """Scan DSA nTDSConnection table and return connection @@ -674,21 +656,21 @@ class DirectoryServiceAgent: text = "%s" % self.connect_table[k] return text -class NTDSConnection(): + +class NTDSConnection(object): """Class defines a nTDSConnection found under a DSA """ def __init__(self, dnstr): - self.dnstr = dnstr - self.enabled = False - self.committed = False # new connection needs to be committed - self.options = 0 - self.flags = 0 + self.dnstr = dnstr + self.enabled = False + self.committed = False # new connection needs to be committed + self.options = 0 + self.flags = 0 self.transport_dnstr = None - self.transport_guid = None - self.from_dnstr = None - self.from_guid = None - self.schedule = None - return + self.transport_guid = None + self.from_dnstr = None + self.from_guid = None + self.schedule = None def __str__(self): '''Debug dump string output of NTDSConnection object''' @@ -728,7 +710,6 @@ class NTDSConnection(): """Given a NTDSConnection object with an prior initialization for the object's DN, search for the DN and load attributes from the samdb. - Raises an Exception on error. """ controls = ["extended_dn:1:1"] attrs = [ "options", @@ -742,9 +723,8 @@ class NTDSConnection(): attrs=attrs, controls=controls) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find nTDSConnection for (%s) - (%s)" % \ + raise Exception("Unable to find nTDSConnection for (%s) - (%s)" % (self.dnstr, estr)) - return msg = res[0] @@ -780,7 +760,6 @@ class NTDSConnection(): # Was loaded from database so connection is currently committed self.committed = True - return def commit_connection(self, samdb): """Given a NTDSConnection object that is not committed in the @@ -800,7 +779,7 @@ class NTDSConnection(): if enum == ldb.ERR_NO_SUCH_OBJECT: found = False else: - raise Exception("Unable to search for (%s) - (%s)" % \ + raise Exception("Unable to search for (%s) - (%s)" % (self.dnstr, estr)) if found: raise Exception("nTDSConnection for (%s) already exists!" % self.dnstr) @@ -811,7 +790,7 @@ class NTDSConnection(): enablestr = "FALSE" # Prepare a message for adding to the samdb - m = ldb.Message() + m = ldb.Message() m.dn = ldb.Dn(samdb, self.dnstr) m["objectClass"] = \ @@ -839,7 +818,6 @@ class NTDSConnection(): raise Exception("Could not add nTDSConnection for (%s) - (%s)" % \ (self.dnstr, estr)) self.committed = True - return def is_schedule_minimum_once_per_week(self): """Returns True if our schedule includes at least one @@ -893,16 +871,16 @@ class NTDSConnection(): '''Return fromServer dn string attribute''' return self.from_dnstr + class Partition(NamingContext): - """Class defines a naming context discovered thru the - Partitions DN of the configuration schema. This is - a more specific form of NamingContext class (inheriting - from that class) and it identifies unique attributes - enumerated in the Partitions such as which nTDSDSAs - are cross referenced for replicas + """A naming context discovered thru Partitions DN of the config schema. + + This is a more specific form of NamingContext class (inheriting from that + class) and it identifies unique attributes enumerated in the Partitions + such as which nTDSDSAs are cross referenced for replicas """ def __init__(self, partstr): - self.partstr = partstr + self.partstr = partstr self.rw_location_list = [] self.ro_location_list = [] @@ -913,14 +891,13 @@ class Partition(NamingContext): def load_partition(self, samdb): - """Given a Partition class object that has been initialized - with its partition dn string, load the partition from the - sam database, identify the type of the partition (schema, - domain, etc) and record the list of nTDSDSAs that appear - in the cross reference attributes msDS-NC-Replica-Locations - and msDS-NC-RO-Replica-Locations. - Raises an Exception on error. - :param samdb: sam database to load partition from + """Given a Partition class object that has been initialized with its + partition dn string, load the partition from the sam database, identify + the type of the partition (schema, domain, etc) and record the list of + nTDSDSAs that appear in the cross reference attributes + msDS-NC-Replica-Locations and msDS-NC-RO-Replica-Locations. + + :param samdb: sam database to load partition from """ controls = ["extended_dn:1:1"] attrs = [ "nCName", @@ -933,7 +910,6 @@ class Partition(NamingContext): except ldb.LdbError, (enum, estr): raise Exception("Unable to find partition for (%s) - (%s)" % ( self.partstr, estr)) - return msg = res[0] for k in msg.keys(): @@ -945,20 +921,19 @@ class Partition(NamingContext): # its methods to parse the extended pieces. # Note we don't really need the exact sid value # but instead only need to know if its present. - dsdn = dsdb_Dn(samdb, value) - guid = dsdn.dn.get_extended_component('GUID') - sid = dsdn.dn.get_extended_component('SID') + dsdn = dsdb_Dn(samdb, value) + guid = dsdn.dn.get_extended_component('GUID') + sid = dsdn.dn.get_extended_component('SID') if guid is None: raise Exception("Missing GUID for (%s) - (%s: %s)" % \ (self.partstr, k, value)) - else: - guid = misc.GUID(guid) + guid = misc.GUID(guid) if k == "nCName": self.nc_dnstr = str(dsdn.dn) - self.nc_guid = guid - self.nc_sid = sid + self.nc_guid = guid + self.nc_sid = sid continue if k == "msDS-NC-Replica-Locations": @@ -973,16 +948,14 @@ class Partition(NamingContext): # enumerated self.identify_by_basedn(samdb) - return - def should_be_present(self, target_dsa): """Tests whether this partition should have an NC replica on the target dsa. This method returns a tuple of needed=True/False, ro=True/False, partial=True/False :param target_dsa: should NC be present on target dsa """ - needed = False - ro = False + needed = False + ro = False partial = False # If this is the config, schema, or default @@ -990,7 +963,7 @@ class Partition(NamingContext): # be present if self.nc_type == NCType.config or \ self.nc_type == NCType.schema or \ - (self.nc_type == NCType.domain and \ + (self.nc_type == NCType.domain and self.nc_dnstr == target_dsa.default_dnstr): needed = True @@ -1013,9 +986,9 @@ class Partition(NamingContext): if target_dsa.is_gc() and \ self.nc_type == NCType.domain and \ self.nc_dnstr != target_dsa.default_dnstr and \ - (target_dsa.dsa_dnstr in self.ro_location_list or \ + (target_dsa.dsa_dnstr in self.ro_location_list or target_dsa.dsa_dnstr in self.rw_location_list): - needed = True + needed = True partial = True # partial NCs are always readonly @@ -1034,38 +1007,35 @@ class Partition(NamingContext): text = text + "\n\tmsDS-NC-RO-Replica-Locations=%s" % k return text -class Site: + +class Site(object): + def __init__(self, site_dnstr): - self.site_dnstr = site_dnstr + self.site_dnstr = site_dnstr self.site_options = 0 - self.dsa_table = {} - return + self.dsa_table = {} def load_site(self, samdb): """Loads the NTDS Site Settions options attribute for the site - Raises an Exception on error. """ ssdn = "CN=NTDS Site Settings,%s" % self.site_dnstr try: res = samdb.search(base=ssdn, scope=ldb.SCOPE_BASE, attrs=["options"]) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find site settings for (%s) - (%s)" % \ + raise Exception("Unable to find site settings for (%s) - (%s)" % (ssdn, estr)) - return msg = res[0] if "options" in msg: self.site_options = int(msg["options"][0]) self.load_all_dsa(samdb) - return def load_all_dsa(self, samdb): """Discover all nTDSDSA thru the sites entry and instantiate and load the DSAs. Each dsa is inserted into the dsa_table by dn string. - Raises an Exception on error. """ try: res = samdb.search(self.site_dnstr, @@ -1088,7 +1058,6 @@ class Site: # Assign this dsa to my dsa table # and index by dsa dn self.dsa_table[dnstr] = dsa - return def get_dsa_by_guidstr(self, guidstr): for dsa in self.dsa_table.values(): @@ -1099,7 +1068,8 @@ class Site: def get_dsa(self, dnstr): """Return a previously loaded DSA object by consulting the sites dsa_table for the provided DSA dn string - Returns None if DSA doesn't exist + + :return: None if DSA doesn't exist """ if dnstr in self.dsa_table.keys(): return self.dsa_table[dnstr] @@ -1107,14 +1077,14 @@ class Site: def is_intrasite_topology_disabled(self): '''Returns True if intrasite topology is disabled for site''' - if (self.site_options & \ + if (self.site_options & dsdb.DS_NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED) != 0: return True return False def should_detect_stale(self): '''Returns True if detect stale is enabled for site''' - if (self.site_options & \ + if (self.site_options & dsdb.DS_NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED) == 0: return True return False @@ -1129,16 +1099,18 @@ class Site: return text -class GraphNode: - """This is a graph node describing a set of edges that should be - directed to it. Each edge is a connection for a particular - naming context replica directed from another node in the forest - to this node. +class GraphNode(object): + """A graph node describing a set of edges that should be directed to it. + + Each edge is a connection for a particular naming context replica directed + from another node in the forest to this node. """ + def __init__(self, dsa_dnstr, max_node_edges): """Instantiate the graph node according to a DSA dn string - :param max_node_edges: maximum number of edges that should ever - be directed to the node + + :param max_node_edges: maximum number of edges that should ever + be directed to the node """ self.max_edges = max_node_edges self.dsa_dnstr = dsa_dnstr @@ -1155,7 +1127,8 @@ class GraphNode: def add_edge_from(self, from_dsa_dnstr): """Add an edge from the dsa to our graph nodes edge from list - :param from_dsa_dnstr: the dsa that the edge emanates from + + :param from_dsa_dnstr: the dsa that the edge emanates from """ assert from_dsa_dnstr is not None @@ -1177,11 +1150,11 @@ class GraphNode: the "fromServer" attribute). If it does then we add an edge from the server unless we are over the max edges for this graph node - :param dsa: dsa with a dnstr equivalent to his graph node + + :param dsa: dsa with a dnstr equivalent to his graph node """ for dnstr, connect in dsa.connect_table.items(): self.add_edge_from(connect.from_dnstr) - return def add_connections_from_edges(self, dsa): """For each edge directed to this graph node, ensure there @@ -1216,11 +1189,11 @@ class GraphNode: dnstr = "CN=%s," % str(uuid.uuid4()) + self.dsa_dnstr connect = NTDSConnection(dnstr) - connect.committed = False - connect.enabled = True - connect.from_dnstr = edge_dnstr - connect.options = dsdb.NTDSCONN_OPT_IS_GENERATED - connect.flags = dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME + \ + connect.committed = False + connect.enabled = True + connect.from_dnstr = edge_dnstr + connect.options = dsdb.NTDSCONN_OPT_IS_GENERATED + connect.flags = dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME + \ dsdb.SYSTEM_FLAG_CONFIG_ALLOW_MOVE # Create schedule. Attribute valuse set according to MS-TECH @@ -1249,23 +1222,22 @@ class GraphNode: dsa.add_connection(dnstr, connect); - return - def has_sufficient_edges(self): '''Return True if we have met the maximum "from edges" criteria''' if len(self.edge_from) >= self.max_edges: return True return False -class Transport(): + +class Transport(object): """Class defines a Inter-site transport found under Sites """ + def __init__(self, dnstr): - self.dnstr = dnstr - self.options = 0 - self.guid = None - self.address_attr = None - return + self.dnstr = dnstr + self.options = 0 + self.guid = None + self.address_attr = None def __str__(self): '''Debug dump string output of Transport object''' @@ -1281,7 +1253,6 @@ class Transport(): """Given a Transport object with an prior initialization for the object's DN, search for the DN and load attributes from the samdb. - Raises an Exception on error. """ attrs = [ "objectGUID", "options", @@ -1291,9 +1262,8 @@ class Transport(): attrs=attrs) except ldb.LdbError, (enum, estr): - raise Exception("Unable to find Transport for (%s) - (%s)" % \ + raise Exception("Unable to find Transport for (%s) - (%s)" % (self.dnstr, estr)) - return msg = res[0] self.guid = misc.GUID(samdb.schema_format_value("objectGUID", @@ -1304,19 +1274,19 @@ class Transport(): if "transportAddressAttribute" in msg: self.address_attr = str(msg["transportAddressAttribute"][0]) - return -class RepsFromTo: +class RepsFromTo(object): """Class encapsulation of the NDR repsFromToBlob. - Removes the necessity of external code having to - understand about other_info or manipulation of - update flags. + + Removes the necessity of external code having to + understand about other_info or manipulation of + update flags. """ def __init__(self, nc_dnstr=None, ndr_blob=None): self.__dict__['to_be_deleted'] = False - self.__dict__['nc_dnstr'] = nc_dnstr - self.__dict__['update_flags'] = 0x0 + self.__dict__['nc_dnstr'] = nc_dnstr + self.__dict__['update_flags'] = 0x0 # WARNING: # @@ -1339,25 +1309,24 @@ class RepsFromTo: # it is necessary to hold a proper python GC reference # count. if ndr_blob is None: - self.__dict__['ndr_blob'] = drsblobs.repsFromToBlob() + self.__dict__['ndr_blob'] = drsblobs.repsFromToBlob() self.__dict__['ndr_blob'].version = 0x1 - self.__dict__['dns_name1'] = None - self.__dict__['dns_name2'] = None + self.__dict__['dns_name1'] = None + self.__dict__['dns_name2'] = None self.__dict__['ndr_blob'].ctr.other_info = \ self.__dict__['other_info'] = drsblobs.repsFromTo1OtherInfo() else: - self.__dict__['ndr_blob'] = ndr_blob + self.__dict__['ndr_blob'] = ndr_blob self.__dict__['other_info'] = ndr_blob.ctr.other_info if ndr_blob.version == 0x1: - self.__dict__['dns_name1'] = ndr_blob.ctr.other_info.dns_name - self.__dict__['dns_name2'] = None + self.__dict__['dns_name1'] = ndr_blob.ctr.other_info.dns_name + self.__dict__['dns_name2'] = None else: - self.__dict__['dns_name1'] = ndr_blob.ctr.other_info.dns_name1 - self.__dict__['dns_name2'] = ndr_blob.ctr.other_info.dns_name2 - return + self.__dict__['dns_name1'] = ndr_blob.ctr.other_info.dns_name1 + self.__dict__['dns_name2'] = ndr_blob.ctr.other_info.dns_name2 def __str__(self): '''Debug dump string output of class''' @@ -1394,9 +1363,9 @@ class RepsFromTo: def __setattr__(self, item, value): - if item in [ 'schedule', 'replica_flags', 'transport_guid', \ - 'source_dsa_obj_guid', 'source_dsa_invocation_id', \ - 'consecutive_sync_failures', 'last_success', \ + if item in [ 'schedule', 'replica_flags', 'transport_guid', + 'source_dsa_obj_guid', 'source_dsa_invocation_id', + 'consecutive_sync_failures', 'last_success', 'last_attempt' ]: setattr(self.__dict__['ndr_blob'].ctr, item, value) @@ -1431,15 +1400,14 @@ class RepsFromTo: else: self.__dict__['update_flags'] |= drsuapi.DRSUAPI_DRS_UPDATE_ADDRESS - return - def __getattr__(self, item): - """Overload of RepsFromTo attribute retrieval. Allows - external code to ignore substructures within the blob + """Overload of RepsFromTo attribute retrieval. + + Allows external code to ignore substructures within the blob """ - if item in [ 'schedule', 'replica_flags', 'transport_guid', \ - 'source_dsa_obj_guid', 'source_dsa_invocation_id', \ - 'consecutive_sync_failures', 'last_success', \ + if item in [ 'schedule', 'replica_flags', 'transport_guid', + 'source_dsa_obj_guid', 'source_dsa_invocation_id', + 'consecutive_sync_failures', 'last_success', 'last_attempt' ]: return getattr(self.__dict__['ndr_blob'].ctr, item) |