diff options
Diffstat (limited to 'source4')
-rwxr-xr-x | source4/scripting/bin/samba_kcc | 350 | ||||
-rw-r--r-- | source4/scripting/python/samba/kcc_utils.py | 150 |
2 files changed, 224 insertions, 276 deletions
diff --git a/source4/scripting/bin/samba_kcc b/source4/scripting/bin/samba_kcc index 583d88f597..2f169a8273 100755 --- a/source4/scripting/bin/samba_kcc +++ b/source4/scripting/bin/samba_kcc @@ -18,10 +18,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os -import tempfile import sys import random -import copy # ensure we get messages out immediately, so they get in the samba logs, # and don't get swallowed by a timeout @@ -39,47 +37,46 @@ sys.path.insert(0, "bin/python") import optparse import logging -from samba import (getopt as options, \ - Ldb, \ - ldb, \ - dsdb, \ - param, \ - read_and_sub_file) -from samba.auth import system_session -from samba.samdb import SamDB -from samba.dcerpc import drsuapi +from samba import ( + getopt as options, + Ldb, + ldb, + dsdb, + read_and_sub_file) +from samba.auth import system_session +from samba.samdb import SamDB +from samba.dcerpc import drsuapi from samba.kcc_utils import * -class KCC: - """The Knowledge Consistency Checker class. A container for - objects and methods allowing a run of the KCC. Produces - a set of connections in the samdb for which the Distributed - Replication Service can then utilize to replicate naming - contexts +class KCC(object): + """The Knowledge Consistency Checker class. + + A container for objects and methods allowing a run of the KCC. Produces a + set of connections in the samdb for which the Distributed Replication + Service can then utilize to replicate naming contexts """ def __init__(self): """Initializes the partitions class which can hold our local DCs partitions or all the partitions in the forest """ - self.part_table = {} # partition objects - self.site_table = {} + self.part_table = {} # partition objects + self.site_table = {} self.transport_table = {} - self.sitelink_table = {} + self.sitelink_table = {} # Used in inter-site topology computation. A list # of connections (by NTDSConnection object) that are # to be kept when pruning un-needed NTDS Connections self.keep_connection_list = [] - self.my_dsa_dnstr = None # My dsa DN - self.my_dsa = None # My dsa object + self.my_dsa_dnstr = None # My dsa DN + self.my_dsa = None # My dsa object self.my_site_dnstr = None - self.my_site = None + self.my_site = None - self.samdb = None - return + self.samdb = None def load_all_transports(self): """Loads the inter-site transport objects for Sites @@ -87,12 +84,13 @@ class KCC: ::returns: Raises an Exception on error """ try: - res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % \ + res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % self.samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE, expression="(objectClass=interSiteTransport)") except ldb.LdbError, (enum, estr): - raise Exception("Unable to find inter-site transports - (%s)" % estr) + raise Exception("Unable to find inter-site transports - (%s)" % + estr) for msg in res: dnstr = str(msg.dn) @@ -109,15 +107,13 @@ class KCC: # and index by dn self.transport_table[dnstr] = transport - return - def load_all_sitelinks(self): """Loads the inter-site siteLink objects ::returns: Raises an Exception on error """ try: - res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % \ + res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % self.samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE, expression="(objectClass=siteLink)") @@ -139,8 +135,6 @@ class KCC: # and index by dn self.sitelink_table[dnstr] = sitelink - return - def get_sitelink(self, site1_dnstr, site2_dnstr): """Return the siteLink (if it exists) that connects the two input site DNs @@ -155,15 +149,14 @@ class KCC: ::returns: Raises an Exception on error """ - self.my_site_dnstr = "CN=%s,CN=Sites,%s" % \ - (self.samdb.server_site_name(), + self.my_site_dnstr = "CN=%s,CN=Sites,%s" % ( + self.samdb.server_site_name(), self.samdb.get_config_basedn()) site = Site(self.my_site_dnstr) site.load_site(self.samdb) self.site_table[self.my_site_dnstr] = site self.my_site = site - return def load_all_sites(self): """Discover all sites and instantiate and load each @@ -190,7 +183,6 @@ class KCC: site.load_site(self.samdb) self.site_table[sitestr] = site - return def load_my_dsa(self): """Discover my nTDSDSA dn thru the rootDSE entry @@ -207,8 +199,6 @@ class KCC: self.my_dsa_dnstr = res[0]["dsServiceName"][0] self.my_dsa = self.my_site.get_dsa(self.my_dsa_dnstr) - return - def load_all_partitions(self): """Discover all NCs thru the Partitions dn and instantiate and load the NCs. @@ -245,13 +235,12 @@ class KCC: for partdn, part in self.part_table.items(): for dsadn, dsa in self.my_site.dsa_table.items(): needed, ro, partial = part.should_be_present(dsa) - logger.info("dsadn:%s\nncdn:%s\nneeded=%s:ro=%s:partial=%s\n" % \ + logger.info("dsadn:%s\nncdn:%s\nneeded=%s:ro=%s:partial=%s\n" % (dsadn, part.nc_dnstr, needed, ro, partial)) - return def refresh_failed_links_connections(self): # XXX - not implemented yet - return + pass def is_stale_link_connection(self, target_dsa): """Returns False if no tuple z exists in the kCCFailedLinks or @@ -264,7 +253,7 @@ class KCC: def remove_unneeded_failed_links_connections(self): # XXX - not implemented yet - return + pass def remove_unneeded_ntdsconn(self, all_connected): """Removes unneeded NTDS Connections after computation @@ -402,8 +391,6 @@ class KCC: # Commit any modified connections mydsa.commit_connections(self.samdb) - return - def get_dsa_by_guidstr(self, guidstr): """Given a DSA guid string, consule all sites looking for the corresponding DSA and return it. @@ -446,7 +433,7 @@ class KCC: drsuapi.DRSUAPI_DRS_UPDATE_ADDRESS """ s_dnstr = s_dsa.dsa_dnstr - update = 0x0 + update = 0x0 if self.my_site.same_site(s_dsa): same_site = True @@ -465,7 +452,7 @@ class KCC: # per week. if cn_conn.is_schedule_minimum_once_per_week(): - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_PER_SYNC) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_PER_SYNC @@ -475,7 +462,7 @@ class KCC: # of one or more FSMO roles in the NC replica. if same_site or n_rep.is_fsmo_role_owner(s_dnstr): - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_INIT_SYNC) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_INIT_SYNC @@ -489,13 +476,13 @@ class KCC: if (cn_conn.option & dsdb.NTDSCONN_OPT_USE_NOTIFY) == 0x0: - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_NEVER_NOTIFY) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_NEVER_NOTIFY elif same_site == False: - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_NEVER_NOTIFY) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_NEVER_NOTIFY @@ -504,11 +491,11 @@ class KCC: # not in the same site and the # NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION bit is # clear in cn!options - if same_site == False and \ - (cn_conn.options & \ - dsdb.NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION) == 0x0: + if (same_site == False and + (cn_conn.options & + dsdb.NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION) == 0x0): - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_USE_COMPRESSION) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_USE_COMPRESSION @@ -516,7 +503,7 @@ class KCC: # if bit NTDSCONN_OPT_TWOWAY_SYNC is set in cn!options. if (cn_conn.options & dsdb.NTDSCONN_OPT_TWOWAY_SYNC) != 0x0: - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_TWOWAY_SYNC) == 0x0: t_repsFrom.replica_flags |= drsuapi.DRSUAPI_DRS_TWOWAY_SYNC @@ -524,12 +511,12 @@ class KCC: # set in t.replicaFlags if and only if cn!enabledConnection = false. if cn_conn.is_enabled() == False: - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_DISABLE_AUTO_SYNC) == 0x0: t_repsFrom.replica_flags |= \ drsuapi.DRSUAPI_DRS_DISABLE_AUTO_SYNC - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_DISABLE_PERIODIC_SYNC) == 0x0: t_repsFrom.replica_flags |= \ drsuapi.DRSUAPI_DRS_DISABLE_PERIODIC_SYNC @@ -599,18 +586,18 @@ class KCC: # We're not currently supporting SMTP replication # so is_smtp_replication_available() is currently # always returning False - if same_site == True or \ - cn_conn.transport_dnstr == None or \ - cn_conn.transport_dnstr.find("CN=IP") == 0 or \ - is_smtp_replication_available() == False: + if (same_site == True or + cn_conn.transport_dnstr == None or + cn_conn.transport_dnstr.find("CN=IP") == 0 or + is_smtp_replication_available() == False): - if (t_repsFrom.replica_flags & \ + if (t_repsFrom.replica_flags & drsuapi.DRSUAPI_DRS_MAIL_REP) != 0x0: t_repsFrom.replica_flags &= ~drsuapi.DRSUAPI_DRS_MAIL_REP null_guid = misc.GUID() - if t_repsFrom.transport_guid is None or \ - t_repsFrom.transport_guid != null_guid: + if (t_repsFrom.transport_guid is None or + t_repsFrom.transport_guid != null_guid): t_repsFrom.transport_guid = null_guid # See (NOTE MS-TECH INCORRECT) above @@ -663,7 +650,7 @@ class KCC: # the DSA object try: pdnstr = s_dsa.get_parent_dnstr() - attrs = [ x_transport.address_attr ] + attrs = [ x_transport.address_attr ] res = self.samdb.search(base=pdnstr, scope=ldb.SCOPE_BASE, attrs=attrs) @@ -691,7 +678,6 @@ class KCC: if t_repsFrom.is_modified(): logger.debug("modify_repsFrom(): %s" % t_repsFrom) - return def is_repsFrom_implied(self, n_rep, cn_conn): """Given a NC replica and NTDS Connection, determine if the connection @@ -748,9 +734,9 @@ class KCC: # cn!transportType has an RDN of CN=IP. # implied = (s_rep.is_ro() == False or n_rep.is_partial() == True) and \ - (n_rep.is_domain() == False or \ - n_rep.is_partial() == True or \ - cn_conn.transport_dnstr == None or \ + (n_rep.is_domain() == False or + n_rep.is_partial() == True or + cn_conn.transport_dnstr == None or cn_conn.transport_dnstr.find("CN=IP") == 0) if implied: @@ -813,7 +799,7 @@ class KCC: # Source dsa is gone from config (strange) # so cleanup stale repsFrom for unlisted DSA if s_dsa is None: - logger.debug("repsFrom source DSA guid (%s) not found" % \ + logger.debug("repsFrom source DSA guid (%s) not found" % guidstr) t_repsFrom.to_be_deleted = True continue @@ -905,8 +891,6 @@ class KCC: # Commit any modified repsFrom to the NC replica n_rep.commit_repsFrom(self.samdb) - return - def keep_connection(self, cn_conn): """Determines if the connection is meant to be kept during the pruning of unneeded connections operation. @@ -930,7 +914,6 @@ class KCC: # from Bridgeheads # XXX - not implemented yet - return def setup_graph(self): """Set up a GRAPH, populated with a VERTEX for each site @@ -943,8 +926,7 @@ class KCC: # XXX - not implemented yet return None - def get_bridgehead(self, site, part, transport, \ - partial_ok, detect_failed): + def get_bridgehead(self, site, part, transport, partial_ok, detect_failed): """Get a bridghead DC. :param site: site object representing for which a bridgehead @@ -961,18 +943,18 @@ class KCC: ::returns: dsa object for the bridgehead DC or None """ - bhs = self.get_all_bridgeheads(site, part, transport, \ + bhs = self.get_all_bridgeheads(site, part, transport, partial_ok, detect_failed) if len(bhs) == 0: - logger.debug("get_bridgehead: exit\n\tsitedn=%s\n\tbhdn=None" % \ + logger.debug("get_bridgehead: exit\n\tsitedn=%s\n\tbhdn=None" % site.site_dnstr) return None else: - logger.debug("get_bridgehead: exit\n\tsitedn=%s\n\tbhdn=%s" % \ + logger.debug("get_bridgehead: exit\n\tsitedn=%s\n\tbhdn=%s" % (site.site_dnstr, bhs[0].dsa_dnstr)) return bhs[0] - def get_all_bridgeheads(self, site, part, transport, \ + def get_all_bridgeheads(self, site, part, transport, partial_ok, detect_failed): """Get all bridghead DCs satisfying the given criteria @@ -1002,8 +984,8 @@ class KCC: # IF t!bridgeheadServerListBL has one or more values and # t!bridgeheadServerListBL does not contain a reference # to the parent object of dc then skip dc - if len(transport.bridgehead_list) != 0 and \ - pdnstr not in transport.bridgehead_list: + if (len(transport.bridgehead_list) != 0 and + pdnstr not in transport.bridgehead_list): continue # IF dc is in the same site as the local DC @@ -1081,8 +1063,8 @@ class KCC: # XXX - not implemented yet return False - def create_connection(self, part, rbh, rsite, transport, \ - lbh, lsite, link_opt, link_sched, \ + def create_connection(self, part, rbh, rsite, transport, + lbh, lsite, link_opt, link_sched, partial_ok, detect_failed): """Create an nTDSConnection object with the given parameters if one does not already exist. @@ -1106,18 +1088,18 @@ class KCC: replication traffic around them, FALSE to assume no DC has failed. """ - rbhs_all = self.get_all_bridgeheads(rsite, part, transport, \ + rbhs_all = self.get_all_bridgeheads(rsite, part, transport, partial_ok, False) # MS-TECH says to compute rbhs_avail but then doesn't use it - # rbhs_avail = self.get_all_bridgeheads(rsite, part, transport, \ + # rbhs_avail = self.get_all_bridgeheads(rsite, part, transport, # partial_ok, detect_failed) - lbhs_all = self.get_all_bridgeheads(lsite, part, transport, \ + lbhs_all = self.get_all_bridgeheads(lsite, part, transport, partial_ok, False) # MS-TECH says to compute lbhs_avail but then doesn't use it - # lbhs_avail = self.get_all_bridgeheads(lsite, part, transport, \ + # lbhs_avail = self.get_all_bridgeheads(lsite, part, transport, # partial_ok, detect_failed) # FOR each nTDSConnection object cn such that the parent of cn is @@ -1136,16 +1118,15 @@ class KCC: # IF bit NTDSCONN_OPT_IS_GENERATED is set in cn!options and # NTDSCONN_OPT_RODC_TOPOLOGY is clear in cn!options and # cn!transportType references t - if cn.is_generated() == True and \ - cn.is_rodc_topology() == False and \ - cn.transport_dnstr == transport.dnstr: + if (cn.is_generated() and not cn.is_rodc_topology() and + cn.transport_dnstr == transport.dnstr): # IF bit NTDSCONN_OPT_USER_OWNED_SCHEDULE is clear in # cn!options and cn!schedule != sch # Perform an originating update to set cn!schedule to # sched - if cn.is_user_owned_schedule() == False and \ - cn.is_equivalent_schedule(link_sched) == False: + if (not cn.is_user_owned_schedule() and + not cn.is_equivalent_schedule(link_sched)): cn.schedule = link_sched cn.set_modified(True) @@ -1259,9 +1240,9 @@ class KCC: # IF (bit NTDSCONN_OPT_IS_GENERATED is clear in cn!options or # cn!transportType references t) and # NTDSCONN_OPT_RODC_TOPOLOGY is clear in cn!options - if (cn.is_generated() == False or \ - cn.transport_dnstr == transport.dnstr) and \ - cn.is_rodc_topology() == False: + if ((not cn.is_generated() or + cn.transport_dnstr == transport.dnstr) and + not cn.is_rodc_topology()): # LET rguid be the objectGUID of the nTDSDSA object # referenced by cn!fromServer @@ -1270,13 +1251,13 @@ class KCC: # IF BridgeheadDCFailed(rguid, detectFailedDCs) = FALSE and # BridgeheadDCFailed(lguid, detectFailedDCs) = FALSE # Increment cValidConnections by 1 - if self.is_bridgehead_failed(rdsa, detect_failed) == False and \ - self.is_bridgehead_failed(ldsa, detect_failed) == False: + if (not self.is_bridgehead_failed(rdsa, detect_failed) and + not self.is_bridgehead_failed(ldsa, detect_failed)): valid_connections += 1 # IF keepConnections does not contain cn!objectGUID # APPEND cn!objectGUID to keepConnections - if self.keep_connection(cn) == False: + if not self.keep_connection(cn): self.keep_connection_list.append(cn) # ENDFOR @@ -1291,7 +1272,7 @@ class KCC: # SET bits NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT and # NTDSCONN_OPT_USE_NOTIFY in opt if (link_opt & dsdb.NTDSSITELINK_OPT_USE_NOTIFY) != 0: - opt |= (dsdb.NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT | \ + opt |= (dsdb.NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT | dsdb.NTDSCONN_USE_NOTIFY) # IF bit NTDSSITELINK_OPT_TWOWAY_SYNC is set in ri.Options @@ -1302,7 +1283,7 @@ class KCC: # IF bit NTDSSITELINK_OPT_DISABLE_COMPRESSION is set in # ri.Options # SET bit NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION in opt - if (link_opt & \ + if (link_opt & dsdb.NTDSSITELINK_OPT_DISABLE_COMPRESSION) != 0: opt |= dsdb.NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION @@ -1322,12 +1303,9 @@ class KCC: lbh.commit_connections(self.samdb) # APPEND cn!objectGUID to keepConnections - if self.keep_connection(cn) == False: + if not self.keep_connection(cn): self.keep_connection_list.append(cn) - return - - def create_connections(self, graph, part, detect_failed): """Construct an NC replica graph for the NC identified by the given crossRef, then create any additional nTDSConnection @@ -1349,9 +1327,9 @@ class KCC: detected. """ all_connected = True - found_failed = False + found_failed = False - logger.debug("create_connections(): enter\n\tpartdn=%s\n\tdetect_failed=%s" % \ + logger.debug("create_connections(): enter\n\tpartdn=%s\n\tdetect_failed=%s" % (part.nc_dnstr, detect_failed)) # XXX - This is a highly abbreviated function from the MS-TECH @@ -1403,20 +1381,20 @@ class KCC: # cr, t, partialReplicaOkay, detectFailedDCs) if self.my_dsa.is_ro(): lsite = self.my_site - lbh = self.my_dsa + lbh = self.my_dsa else: lsite = self.my_site - lbh = self.get_bridgehead(lsite, part, transport, + lbh = self.get_bridgehead(lsite, part, transport, partial_ok, detect_failed) # Find the siteLink object that enumerates the connection # between the two sites if it is present sitelink = self.get_sitelink(lsite.site_dnstr, rsite.site_dnstr) if sitelink is None: - link_opt = 0x0 + link_opt = 0x0 link_sched = None else: - link_opt = sitelink.options + link_opt = sitelink.options link_sched = sitelink.schedule self.create_connection(part, rbh, rsite, transport, @@ -1454,10 +1432,10 @@ class KCC: for part in self.part_table.values(): - if part.is_enabled() == False: + if not part.is_enabled(): continue - if part.is_foreign() == True: + if part.is_foreign(): continue graph = self.setup_graph() @@ -1468,7 +1446,7 @@ class KCC: connected, found_failed = self.create_connections(graph, part, True) - if connected == False: + if not connected: all_connected = False if found_failed: @@ -1491,7 +1469,7 @@ class KCC: """ # Retrieve my DSA - mydsa = self.my_dsa + mydsa = self.my_dsa mysite = self.my_site all_connected = True @@ -1505,12 +1483,12 @@ class KCC: # Test whether local site has topology disabled if mysite.is_intersite_topology_disabled(): - logger.debug("intersite(): exit disabled all_connected=%d" % \ + logger.debug("intersite(): exit disabled all_connected=%d" % all_connected) return all_connected - if mydsa.is_istg() == False: - logger.debug("intersite(): exit not istg all_connected=%d" % \ + if not mydsa.is_istg(): + logger.debug("intersite(): exit not istg all_connected=%d" % all_connected) return all_connected @@ -1538,15 +1516,13 @@ class KCC: # that the following is true: # # cn1.fromServer = cn2.fromServer - # cn1.schedule = cn2.schedule + # cn1.schedule = cn2.schedule # # If no such cn2 can be found, cn1 is not modified. # If no such cn1 can be found, nothing is modified by this task. # XXX - not implemented yet - return - def intrasite_max_node_edges(self, node_count): """Returns the maximum number of edges directed to a node in the intrasite replica graph. @@ -1586,32 +1562,32 @@ class KCC: # for NC (x) # l_of_x - replica (l) is the local replica for NC (x) # that should appear on the local DC - # r_len = is length of replica list |R| + # r_len = is length of replica list |R| # # If the DSA doesn't need a replica for this # partition (NC x) then continue needed, ro, partial = nc_x.should_be_present(dc_local) - logger.debug("construct_intrasite_graph(): enter" + \ - "\n\tgc_only=%d" % gc_only + \ - "\n\tdetect_stale=%d" % detect_stale + \ - "\n\tneeded=%s" % needed + \ - "\n\tro=%s" % ro + \ - "\n\tpartial=%s" % partial + \ + logger.debug("construct_intrasite_graph(): enter" + + "\n\tgc_only=%d" % gc_only + + "\n\tdetect_stale=%d" % detect_stale + + "\n\tneeded=%s" % needed + + "\n\tro=%s" % ro + + "\n\tpartial=%s" % partial + "\n%s" % nc_x) - if needed == False: + if not needed: return # Create a NCReplica that matches what the local replica # should say. We'll use this below in our r_list - l_of_x = NCReplica(dc_local.dsa_dnstr, dc_local.dsa_guid, \ + l_of_x = NCReplica(dc_local.dsa_dnstr, dc_local.dsa_guid, nc_x.nc_dnstr) l_of_x.identify_by_basedn(self.samdb) - l_of_x.rep_partial = partial - l_of_x.rep_ro = ro + l_of_x.rep_partial = partial + l_of_x.rep_ro = ro # Add this replica that "should be present" to the # needed replica table for this DSA @@ -1636,13 +1612,13 @@ class KCC: f_of_x = dc_s.current_rep_table[nc_x.nc_dnstr] # Replica (f) of NC (x) must be writable - if f_of_x.is_ro() == True: + if f_of_x.is_ro(): continue # Replica (f) of NC (x) must satisfy the # "is present" criteria for DC (s) that # it was found on - if f_of_x.is_present() == False: + if not f_of_x.is_present(): continue # DC (s) must be a writable DSA other than @@ -1654,7 +1630,7 @@ class KCC: # Certain replica graphs are produced only # for global catalogs, so test against # method input parameter - if gc_only and dc_s.is_gc() == False: + if gc_only and not dc_s.is_gc(): continue # DC (s) must be in the same site as the local DC @@ -1675,8 +1651,8 @@ class KCC: # considerations for RODC which state that to deploy # an RODC, at least one writable domain controller in # the domain must be running Windows Server 2008 - if ro and partial == False and nc_x.nc_type == NCType.domain: - if dc_s.is_minimum_behavior(DS_BEHAVIOR_WIN2008) == False: + if ro and not partial and nc_x.nc_type == NCType.domain: + if not dc_s.is_minimum_behavior(DS_BEHAVIOR_WIN2008): continue # If we haven't been told to turn off stale connection @@ -1711,13 +1687,13 @@ class KCC: p_of_x = dsa.current_rep_table[nc_x.nc_dnstr] # Replica (p) of NC (x) must be partial - if p_of_x.is_partial() == False: + if not p_of_x.is_partial(): continue # Replica (p) of NC (x) must satisfy the # "is present" criteria for DC (s) that # it was found on - if p_of_x.is_present() == False: + if not p_of_x.is_present(): continue # DC (s) must be a writable DSA other than @@ -1729,7 +1705,7 @@ class KCC: # Certain replica graphs are produced only # for global catalogs, so test against # method input parameter - if gc_only and dc_s.is_gc() == False: + if gc_only and not dc_s.is_gc(): continue # DC (s) must be in the same site as the local DC @@ -1748,8 +1724,8 @@ class KCC: # replica is needed on a local DC global catalog. There # is no minimum windows behavior for those since GCs # have always been present. - if ro and partial == False and nc_x.nc_type == NCType.domain: - if dc_s.is_minimum_behavior(DS_BEHAVIOR_WIN2008) == False: + if ro and not partial and nc_x.nc_type == NCType.domain: + if not dc_s.is_minimum_behavior(DS_BEHAVIOR_WIN2008): continue # If we haven't been told to turn off stale connection @@ -1783,27 +1759,23 @@ class KCC: while i < (r_len-1): # Add an edge from r(i) to r(i+1) if r(i) is a full # replica or r(i+1) is a partial replica - if r_list[i].is_partial() == False or \ - r_list[i+1].is_partial() == True: + if not r_list[i].is_partial() or r_list[i+1].is_partial(): graph_list[i+1].add_edge_from(r_list[i].rep_dsa_dnstr) # Add an edge from r(i+1) to r(i) if r(i+1) is a full # replica or ri is a partial replica. - if r_list[i+1].is_partial() == False or \ - r_list[i].is_partial() == True: + if not r_list[i+1].is_partial() or r_list[i].is_partial(): graph_list[i].add_edge_from(r_list[i+1].rep_dsa_dnstr) i = i + 1 # Add an edge from r|R|-1 to r0 if r|R|-1 is a full replica # or r0 is a partial replica. - if r_list[r_len-1].is_partial() == False or \ - r_list[0].is_partial() == True: + if not r_list[r_len-1].is_partial() or r_list[0].is_partial(): graph_list[0].add_edge_from(r_list[r_len-1].rep_dsa_dnstr) # Add an edge from r0 to r|R|-1 if r0 is a full replica or # r|R|-1 is a partial replica. - if r_list[0].is_partial() == False or \ - r_list[r_len-1].is_partial() == True: + if not r_list[0].is_partial() or r_list[r_len-1].is_partial(): graph_list[r_len-1].add_edge_from(r_list[0].rep_dsa_dnstr) # For each existing nTDSConnection object implying an edge @@ -1818,7 +1790,7 @@ class KCC: i = 0 while i < r_len: - tnode = graph_list[i] + tnode = graph_list[i] # To optimize replication latency in sites with many NC replicas, the # KCC adds new edges directed to ri to bring the total edges to n+2, @@ -1882,8 +1854,7 @@ class KCC: # Loop thru all the partitions. for partdn, part in self.part_table.items(): - self.construct_intrasite_graph(mysite, mydsa, part, \ - False, \ + self.construct_intrasite_graph(mysite, mydsa, part, False, detect_stale) # If the DC is a GC server, the KCC constructs an additional NC @@ -1892,8 +1863,7 @@ class KCC: # on GC servers are added to R. for partdn, part in self.part_table.items(): if part.is_config(): - self.construct_intrasite_graph(mysite, mydsa, part, \ - True, \ + self.construct_intrasite_graph(mysite, mydsa, part, True, detect_stale) # The DC repeats the NC replica graph computation and nTDSConnection @@ -1905,8 +1875,7 @@ class KCC: # Loop thru all the partitions. for partdn, part in self.part_table.items(): - self.construct_intrasite_graph(mysite, mydsa, part, \ - False, \ + self.construct_intrasite_graph(mysite, mydsa, part, False, False) # don't detect stale # If the DC is a GC server, the KCC constructs an additional NC @@ -1915,8 +1884,7 @@ class KCC: # on GC servers are added to R. for partdn, part in self.part_table.items(): if part.is_config(): - self.construct_intrasite_graph(mysite, mydsa, part, \ - True, \ + self.construct_intrasite_graph(mysite, mydsa, part, True, False) # don't detect stale if opts.readonly: @@ -1934,8 +1902,6 @@ class KCC: # Commit any newly created connections to the samdb mydsa.commit_connections(self.samdb) - return - def run(self, dburl, lp, creds): """Method to perform a complete run of the KCC and produce an updated topology for subsequent NC replica @@ -1950,7 +1916,7 @@ class KCC: credentials=creds, lp=lp) except ldb.LdbError, (num, msg): - logger.error("Unable to open sam database %s : %s" % \ + logger.error("Unable to open sam database %s : %s" % (lp.samdb_url(), msg)) return 1 @@ -2061,7 +2027,7 @@ class KCC: session_info=system_session(), credentials=creds, lp=lp) except ldb.LdbError, (enum, estr): - logger.error("Unable to open sam database (%s) : %s" % \ + logger.error("Unable to open sam database (%s) : %s" % (lp.samdb_url(), estr)) return 1 @@ -2091,7 +2057,7 @@ class KCC: "msDS-NC-RO-Replica-Locations" ] sstr = "CN=Partitions,%s" % self.samdb.get_config_basedn() - res = self.samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRef)") @@ -2109,7 +2075,7 @@ class KCC: "msDS-EnabledFeature" ] sstr = "CN=Partitions,%s" % self.samdb.get_config_basedn() - res = self.samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRefContainer)") @@ -2123,7 +2089,7 @@ class KCC: "whenChanged", "systemFlags" ] - sstr = "CN=Sites,%s" % self.samdb.get_config_basedn() + sstr = "CN=Sites,%s" % self.samdb.get_config_basedn() sites = self.samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=site)") @@ -2145,7 +2111,7 @@ class KCC: "options" ] sstr = "CN=NTDS Site Settings,%s" % sitestr - res = self.samdb.search(base=sstr, scope=ldb.SCOPE_BASE, + res = self.samdb.search(base=sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Write Site Settings output @@ -2164,7 +2130,7 @@ class KCC: "msDS-HasDomainNCs", "msDS-hasFullReplicaNCs", "msDS-HasInstantiatedNCs" ] - attrs = [ "objectClass", + attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", @@ -2186,7 +2152,7 @@ class KCC: for value in msg[k]: # Some of these have binary DNs so # use dsdb_Dn to split out relevent parts - dsdn = dsdb_Dn(self.samdb, value) + dsdn = dsdb_Dn(self.samdb, value) dnstr = str(dsdn.dn) if dnstr not in nclist: nclist.append(dnstr) @@ -2229,7 +2195,7 @@ class KCC: sstr = "CN=Inter-Site Transports,CN=Sites,%s" % \ self.samdb.get_config_basedn() - res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=interSiteTransport)") @@ -2250,7 +2216,7 @@ class KCC: sstr = "CN=Sites,%s" % \ self.samdb.get_config_basedn() - res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLink)") @@ -2264,9 +2230,8 @@ class KCC: "whenChanged", "siteLinkList" ] - sstr = "CN=Sites,%s" % \ - self.samdb.get_config_basedn() - res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, + sstr = "CN=Sites,%s" % self.samdb.get_config_basedn() + res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLinkBridge)") @@ -2282,7 +2247,7 @@ class KCC: "systemFlags" ] sstr = "CN=Sites,%s" % self.samdb.get_config_basedn() - res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=serversContainer)") @@ -2302,7 +2267,7 @@ class KCC: "mailAddress" ] sstr = "CN=Sites,%s" % self.samdb.get_config_basedn() - res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, + res = self.samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=server)") @@ -2339,7 +2304,7 @@ class KCC: "dsServiceName" ] sstr = "" - res = self.samdb.search(sstr, scope=ldb.SCOPE_BASE, + res = self.samdb.search(sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Record the rootDSE object as a dn as it @@ -2382,52 +2347,51 @@ def write_search_result(samdb, f, res): for msg in res: lstr = samdb.write_ldif(msg, ldb.CHANGETYPE_NONE) f.write("%s" % lstr) - return ################################################## # samba_kcc entry point ################################################## -parser = optparse.OptionParser("samba_kcc [options]") +parser = optparse.OptionParser("samba_kcc [options]") sambaopts = options.SambaOptions(parser) -credopts = options.CredentialsOptions(parser) +credopts = options.CredentialsOptions(parser) parser.add_option_group(sambaopts) parser.add_option_group(credopts) parser.add_option_group(options.VersionOptions(parser)) -parser.add_option("--readonly", \ - help="compute topology but do not update database", \ +parser.add_option("--readonly", + help="compute topology but do not update database", action="store_true") -parser.add_option("--debug", \ - help="debug output", \ +parser.add_option("--debug", + help="debug output", action="store_true") -parser.add_option("--seed", \ - help="random number seed", \ +parser.add_option("--seed", + help="random number seed", type=str, metavar="<number>") -parser.add_option("--importldif", \ - help="import topology ldif file", \ +parser.add_option("--importldif", + help="import topology ldif file", type=str, metavar="<file>") -parser.add_option("--exportldif", \ - help="export topology ldif file", \ +parser.add_option("--exportldif", + help="export topology ldif file", type=str, metavar="<file>") -parser.add_option("-H", "--URL" , \ - help="LDB URL for database or target server", \ +parser.add_option("-H", "--URL" , + help="LDB URL for database or target server", type=str, metavar="<URL>", dest="dburl") -parser.add_option("--tmpdb", \ - help="schemaless database file to create for ldif import", \ +parser.add_option("--tmpdb", + help="schemaless database file to create for ldif import", type=str, metavar="<file>") logger = logging.getLogger("samba_kcc") logger.addHandler(logging.StreamHandler(sys.stdout)) -lp = sambaopts.get_loadparm() +lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) opts, args = parser.parse_args() diff --git a/source4/scripting/python/samba/kcc_utils.py b/source4/scripting/python/samba/kcc_utils.py index 93096e9689..a5cda634ba 100644 --- a/source4/scripting/python/samba/kcc_utils.py +++ b/source4/scripting/python/samba/kcc_utils.py @@ -22,12 +22,14 @@ import ldb import uuid import time -from samba import (dsdb, unix2nttime) -from samba.dcerpc import (drsblobs, \ - drsuapi, \ - misc) +from samba import dsdb, unix2nttime +from samba.dcerpc import ( + drsblobs, + drsuapi, + misc, + ) from samba.common import dsdb_Dn -from samba.ndr import (ndr_unpack, ndr_pack) +from samba.ndr import (ndr_unpack, ndr_pack) class NCType(object): @@ -47,9 +49,9 @@ class NamingContext(object): :param nc_dnstr: NC dn string """ self.nc_dnstr = nc_dnstr - self.nc_guid = None - self.nc_sid = None - self.nc_type = NCType.unknown + self.nc_guid = None + self.nc_sid = None + self.nc_type = NCType.unknown def __str__(self): '''Debug dump string output of class''' @@ -83,7 +85,6 @@ class NamingContext(object): self.nc_sid = msg["objectSid"][0] assert self.nc_guid is not None - return def is_schema(self): '''Return True if NC is schema''' @@ -415,7 +416,6 @@ class NCReplica(NamingContext): # Possibly no fSMORoleOwner if "fSMORoleOwner" in msg: self.rep_fsmo_role_owner = msg["fSMORoleOwner"] - return def is_fsmo_role_owner(self, dsa_dnstr): if self.rep_fsmo_role_owner is not None and \ @@ -423,6 +423,7 @@ class NCReplica(NamingContext): return True return False + class DirectoryServiceAgent(object): def __init__(self, dsa_dnstr): @@ -626,7 +627,7 @@ class DirectoryServiceAgent(object): for value in res[0][k]: # Turn dn into a dsdb_Dn so we can use # its methods to parse a binary DN - dsdn = dsdb_Dn(samdb, value) + dsdn = dsdb_Dn(samdb, value) flags = dsdn.get_binary_integer() dnstr = str(dsdn.dn) @@ -712,8 +713,6 @@ class DirectoryServiceAgent(object): for dnstr in delconn: del self.connect_table[dnstr] - return - def add_connection(self, dnstr, connect): assert dnstr not in self.connect_table.keys() self.connect_table[dnstr] = connect @@ -768,12 +767,12 @@ class DirectoryServiceAgent(object): """ dnstr = "CN=%s," % str(uuid.uuid4()) + self.dsa_dnstr - connect = NTDSConnection(dnstr) + connect = NTDSConnection(dnstr) connect.to_be_added = True - connect.enabled = True - connect.from_dnstr = from_dnstr - connect.options = options - connect.flags = flags + connect.enabled = True + connect.from_dnstr = from_dnstr + connect.options = options + connect.flags = flags if transport is not None: connect.transport_dnstr = transport.dnstr @@ -814,11 +813,11 @@ class NTDSConnection(object): """ def __init__(self, dnstr): self.dnstr = dnstr - self.guid = None + self.guid = None self.enabled = False self.whenCreated = 0 - self.to_be_added = False # new connection needs to be added - self.to_be_deleted = False # old connection needs to be deleted + self.to_be_added = False # new connection needs to be added + self.to_be_deleted = False # old connection needs to be deleted self.to_be_modified = False self.options = 0 self.system_flags = 0 @@ -936,12 +935,11 @@ class NTDSConnection(object): if "objectGUID" in res[0]: self.transport_dnstr = tdnstr - self.transport_guid = \ + self.transport_guid = \ misc.GUID(samdb.schema_format_value("objectGUID", msg["objectGUID"][0])) assert self.transport_dnstr is not None assert self.transport_guid is not None - return def commit_deleted(self, samdb, ro=False): """Local helper routine for commit_connections() which @@ -961,8 +959,6 @@ class NTDSConnection(object): raise Exception("Could not delete nTDSConnection for (%s) - (%s)" % \ (self.dnstr, estr)) - return - def commit_added(self, samdb, ro=False): """Local helper routine for commit_connections() which handles committed connections that are to be added to the @@ -1030,7 +1026,6 @@ class NTDSConnection(object): except ldb.LdbError, (enum, estr): raise Exception("Could not add nTDSConnection for (%s) - (%s)" % \ (self.dnstr, estr)) - return def commit_modified(self, samdb, ro=False): """Local helper routine for commit_connections() which @@ -1057,7 +1052,7 @@ class NTDSConnection(object): raise Exception("Unable to search for (%s) - (%s)" % \ (self.dnstr, estr)) if found == False: - raise Exception("nTDSConnection for (%s) doesn't exist!" % \ + raise Exception("nTDSConnection for (%s) doesn't exist!" % self.dnstr) if self.enabled: @@ -1070,53 +1065,47 @@ class NTDSConnection(object): m.dn = ldb.Dn(samdb, self.dnstr) m["enabledConnection"] = \ - ldb.MessageElement(enablestr, ldb.FLAG_MOD_REPLACE, \ + ldb.MessageElement(enablestr, ldb.FLAG_MOD_REPLACE, "enabledConnection") m["fromServer"] = \ - ldb.MessageElement(self.from_dnstr, ldb.FLAG_MOD_REPLACE, \ + ldb.MessageElement(self.from_dnstr, ldb.FLAG_MOD_REPLACE, "fromServer") m["options"] = \ - ldb.MessageElement(str(self.options), ldb.FLAG_MOD_REPLACE, \ + ldb.MessageElement(str(self.options), ldb.FLAG_MOD_REPLACE, "options") m["systemFlags"] = \ - ldb.MessageElement(str(self.system_flags), ldb.FLAG_MOD_REPLACE, \ + ldb.MessageElement(str(self.system_flags), ldb.FLAG_MOD_REPLACE, "systemFlags") if self.transport_dnstr is not None: m["transportType"] = \ - ldb.MessageElement(str(self.transport_dnstr), \ + ldb.MessageElement(str(self.transport_dnstr), ldb.FLAG_MOD_REPLACE, "transportType") else: m["transportType"] = \ - ldb.MessageElement([], \ - ldb.FLAG_MOD_DELETE, "transportType") + ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "transportType") if self.schedule is not None: m["schedule"] = \ - ldb.MessageElement(ndr_pack(self.schedule), \ + ldb.MessageElement(ndr_pack(self.schedule), ldb.FLAG_MOD_REPLACE, "schedule") else: m["schedule"] = \ - ldb.MessageElement([], \ - ldb.FLAG_MOD_DELETE, "schedule") + ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "schedule") try: samdb.modify(m) except ldb.LdbError, (enum, estr): - raise Exception("Could not modify nTDSConnection for (%s) - (%s)" % \ + raise Exception("Could not modify nTDSConnection for (%s) - (%s)" % (self.dnstr, estr)) - return def set_modified(self, truefalse): self.to_be_modified = truefalse - return def set_added(self, truefalse): self.to_be_added = truefalse - return def set_deleted(self, truefalse): self.to_be_deleted = truefalse - return def is_schedule_minimum_once_per_week(self): """Returns True if our schedule includes at least one @@ -1142,9 +1131,9 @@ class NTDSConnection(object): elif sched is None: return True - if self.schedule.size != sched.size or \ - self.schedule.bandwidth != sched.bandwidth or \ - self.schedule.numberOfSchedules != sched.numberOfSchedules: + if (self.schedule.size != sched.size or + self.schedule.bandwidth != sched.bandwidth or + self.schedule.numberOfSchedules != sched.numberOfSchedules): return False for i, header in enumerate(self.schedule.headerArray): @@ -1307,7 +1296,7 @@ class Partition(NamingContext): continue for value in msg[k]: - dsdn = dsdb_Dn(samdb, value) + dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if k == "nCName": @@ -1406,11 +1395,11 @@ class Site(object): naming context. Contains all DSAs that exist within the site """ def __init__(self, site_dnstr): - self.site_dnstr = site_dnstr - self.site_options = 0 + self.site_dnstr = site_dnstr + self.site_options = 0 self.site_topo_generator = None - self.site_topo_failover = 0 # appears to be in minutes - self.dsa_table = {} + self.site_topo_failover = 0 # appears to be in minutes + self.dsa_table = {} def load_site(self, samdb): """Loads the NTDS Site Settions options attribute for the site @@ -1502,7 +1491,7 @@ class Site(object): break if c_rep is None: - raise Exception("Unable to find config NC replica for (%s)" % \ + raise Exception("Unable to find config NC replica for (%s)" % mydsa.dsa_dnstr) # Load repsFrom if not already loaded so we can get the current @@ -1525,10 +1514,10 @@ class Site(object): # in the site by guid in ascending order". Place sorted list # in D_sort[] D_sort = [] - d_dsa = None + d_dsa = None unixnow = int(time.time()) # seconds since 1970 - ntnow = unix2nttime(unixnow) # double word number of 100 nanosecond + ntnow = unix2nttime(unixnow) # double word number of 100 nanosecond # intervals since 1600s for dsa in self.dsa_table.values(): @@ -1583,15 +1572,14 @@ class Site(object): # last_success appears to be a double word containing # number of 100 nanosecond intervals since the 1600s if d_dsa.dsa_ivid != c_rep.source_dsa_invocation_id: - i_idx = j_idx + i_idx = j_idx t_time = 0 elif ntnow < (c_rep.last_success - f): - i_idx = 0 + i_idx = 0 t_time = 0 - else: - i_idx = j_idx + i_idx = j_idx t_time = c_rep.last_success # Otherwise (Nominate local DC as ISTG): @@ -1599,7 +1587,7 @@ class Site(object): # object for the local DC. # Let t = the current time. else: - i_idx = D_sort.index(mydsa) + i_idx = D_sort.index(mydsa) t_time = ntnow # Compute a function that maintains the current ISTG if @@ -1641,14 +1629,15 @@ class Site(object): m.dn = ldb.Dn(samdb, ssdn) m["interSiteTopologyGenerator"] = \ - ldb.MessageElement(mydsa.dsa_dnstr, ldb.FLAG_MOD_REPLACE, \ + ldb.MessageElement(mydsa.dsa_dnstr, ldb.FLAG_MOD_REPLACE, "interSiteTopologyGenerator") try: samdb.modify(m) except ldb.LdbError, estr: - raise Exception("Could not set interSiteTopologyGenerator for (%s) - (%s)" % - (ssdn, estr)) + raise Exception( + "Could not set interSiteTopologyGenerator for (%s) - (%s)" % + (ssdn, estr)) return True def is_intrasite_topology_disabled(self): @@ -1791,13 +1780,11 @@ class GraphNode(object): return # Generate a new dnstr for this nTDSConnection - opt = dsdb.NTDSCONN_OPT_IS_GENERATED + opt = dsdb.NTDSCONN_OPT_IS_GENERATED flags = dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME + \ dsdb.SYSTEM_FLAG_CONFIG_ALLOW_MOVE dsa.create_connection(opt, flags, None, edge_dnstr, None) - return - def has_sufficient_edges(self): '''Return True if we have met the maximum "from edges" criteria''' @@ -1806,7 +1793,6 @@ class GraphNode(object): return False - class Transport(object): """Class defines a Inter-site transport found under Sites """ @@ -1865,11 +1851,11 @@ class Transport(object): if "bridgeheadServerListBL" in msg: for value in msg["bridgeheadServerListBL"]: - dsdn = dsdb_Dn(samdb, value) + dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if dnstr not in self.bridgehead_list: self.bridgehead_list.append(dnstr) - return + class RepsFromTo(object): """Class encapsulation of the NDR repsFromToBlob. @@ -2002,7 +1988,6 @@ class RepsFromTo(object): raise AttributeError, "Unknown attribute %s" % item self.__dict__['update_flags'] |= drsuapi.DRSUAPI_DRS_UPDATE_ADDRESS - return def __getattr__(self, item): """Overload of RepsFromTo attribute retrieval. @@ -2047,18 +2032,19 @@ class RepsFromTo(object): def set_unmodified(self): self.__dict__['update_flags'] = 0x0 + class SiteLink(object): """Class defines a site link found under sites """ def __init__(self, dnstr): - self.dnstr = dnstr - self.options = 0 + self.dnstr = dnstr + self.options = 0 self.system_flags = 0 - self.cost = 0 - self.schedule = None - self.interval = None - self.site_list = [] + self.cost = 0 + self.schedule = None + self.interval = None + self.site_list = [] def __str__(self): '''Debug dump string output of Transport object''' @@ -2124,33 +2110,32 @@ class SiteLink(object): if "siteList" in msg: for value in msg["siteList"]: - dsdn = dsdb_Dn(samdb, value) + dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if dnstr not in self.site_list: self.site_list.append(dnstr) - return def is_sitelink(self, site1_dnstr, site2_dnstr): """Given a siteLink object, determine if it is a link between the two input site DNs """ - if site1_dnstr in self.site_list and \ - site2_dnstr in self.site_list: + if site1_dnstr in self.site_list and site2_dnstr in self.site_list: return True return False -class VertexColor(): + +class VertexColor(object): (unknown, white, black, red) = range(0, 4) + class Vertex(object): """Class encapsulation of a Site Vertex in the intersite topology replication algorithm """ def __init__(self, site, part): - self.site = site - self.part = part + self.site = site + self.part = part self.color = VertexColor.unknown - return def color_vertex(self): """Color each vertex to indicate which kind of NC @@ -2179,7 +2164,6 @@ class Vertex(object): break else: self.color = VertexColor.black - return def is_red(self): assert(self.color != VertexColor.unknown) |