[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Thu Dec 24 06:17:02 UTC 2015


The branch, master has been updated
       via  5b1a87e dsdb subnets: warn when an IPv6 address is in IPv4 embedding range
       via  906a53f samldb: ensure subnets have proper net ranges
       via  cbb9397 samba-tool: add sites subnet subcommands
       via  8e6f2d9 samba-tool tests: Add command line tests for sites
       via  12813ea python/sites: Rework site  DN construction
       via  dbcb13c python.sites tests: remove excessive transaction management
       via  bdb03c5 selftest: Allow sites test to run against a remote ldap:// host
       via  9ac5e3c samba.sites: reduce code duplication in Exception classes
       via  358c0f2 dsdb.tests.sites: don't use global database, tidy long lines
       via  b27dcb5 samba.sites: improve grammar in an error message
       via  f26b227 dsdb.tests.sites: merge interdependent tests
       via  fa2c668 samba-tool sites: use -H to set URL with standard handling
       via  bb64abf sambatool sites: PEP8/flake8 improvements
       via  149c075 torture/gentest time_skew(): don't use labs() on unsigned NTTIME
       via  d098e9c repl: Skip new subdomains and partitions when replicating
      from  8091f84 s4:samba-tool domain raise tool - make it aware of newer domain function levels

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 5b1a87e344f192ae6c43e11c5e62e5cabf8520d3
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Dec 23 12:44:31 2015 +1300

    dsdb subnets: warn when an IPv6 address is in IPv4 embedding range
    
    We fail on these ones, and it isn't immediately obvious why. Windows
    also fails on *most* of them, but succeeds on "::ffff:0:0" which is a
    bit strange but there you go.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Pair-programmed-with: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Thu Dec 24 07:16:25 CET 2015 on sn-devel-144

commit 906a53f442797942e29c899fb7a54a92f970e67e
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Sep 23 15:10:56 2015 +1200

    samldb: ensure subnets have proper net ranges
    
    A subnet name needs to be a valid CIDR address range -- that's the
    ones that look like 10.9.8.0/22, where the number after the /
    determines how many bits are in the address suffix. It can be IPv4 or
    IPv6. There are a few odd constraints (see MS-ADTS v20150630
    6.1.1.2.2.2.1 "Subnet Object") -- for example, with IPv4, the implied
    bit mask can't equal the address. That is, you can't have a subnet
    named "255.255.255.0/24" in a Windows subnet. This rule does not apply
    to IPv6.
    
    Windows and Samba both make some ensure that subnets have a unique
    valid name, though unfortunately Windows 2008R2 is rather slack when
    it comes to IPv6. We follow Windows 2012R2, which roughly follows
    RFC5952 -- with one caveat: Windows will allow an address like
    "::ffff:0:1:2", which translates to the IPv4 address "0.1.0.2" using
    the SIIT translation scheme, and which inet_ntop() would render as
    "::ffff:0:0.1.0.2". In the Samba implementation we use an inet_pton()/
    inet_ntop() round-trip to establish canonicality, so these addresses
    fail. Windows wisely does not allow the SIIT style addresses (the
    acronym is widely agreed to be off-by-one in the second letter), and
    it will regard "::ffff:0:1:2" as simply "::ffff:0:1:2" and allow it.
    We would like to do that too.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit cbb93977cd0e427ba83c2f3dff31668901ad4699
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Oct 28 12:20:37 2015 +1300

    samba-tool: add sites subnet subcommands
    
    This allows you to add, remove, or shift subnets.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8e6f2d923c9fc4249d162c8731fbbf5b44e87936
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 18:16:49 2015 +1200

    samba-tool tests: Add command line tests for sites
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 12813ea55518f7f953a80041e8d5dd1ae2107510
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Oct 29 16:34:27 2015 +1300

    python/sites: Rework site  DN construction
    
    This new routine is safe against escape characters and works
    against Windows 2012R2.
    
    The dn= filter in the old code was samba-specific.
    
    Andrew Bartlett
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit dbcb13cb055f47926901e442d09ecb6fa77d1502
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Oct 29 14:54:15 2015 +1300

    python.sites tests: remove excessive transaction management
    
    These are atomic anyway.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit bdb03c52296ba2af20c2d8c1bd0f017d9f01b9cc
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Oct 28 15:26:12 2015 +1300

    selftest: Allow sites test to run against a remote ldap:// host
    
    The previous code was just broken
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 9ac5e3cf30c62d4a83122e5b9c1b3ef253f126e8
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 18:07:32 2015 +1200

    samba.sites: reduce code duplication in Exception classes
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 358c0f20ccad2063bfab1b4c05a0709951960389
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 18:28:09 2015 +1200

    dsdb.tests.sites: don't use global database, tidy long lines
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b27dcb5bcabf3289de6a81b4a6e740e3c4f7d469
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 18:10:03 2015 +1200

    samba.sites: improve grammar in an error message
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit f26b227041e90b48c3ad659b461b82fed4fe0bfe
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 11:35:55 2015 +1200

    dsdb.tests.sites: merge interdependent tests
    
    The delete test deleted the site made by the create test, which worked
    because "delete" sorts after "create" alphabetically.  By themselves,
    "delete" would fail and "create" would neglect its duty to clean up.
    This would be an issue if the order of tests changes, if one of the
    tests is not run, or if another test appears in between. Everything is
    fine if they give up the pretense of independence.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit fa2c6685c933e44bd504ff98200dc21d3167285a
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Sep 16 14:17:25 2015 +1200

    samba-tool sites: use -H to set URL with standard handling
    
    samba-tool sites was defaulting to the local database, but we might
    want to use another URL. This allows that case while defaulting to
    the old behaviour.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit bb64abf9540118b739ac981eb7f7f2537aceafdd
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Sep 17 18:30:28 2015 +1200

    sambatool sites: PEP8/flake8 improvements
    
    We were nearly there, so lets make the jump. This involves removing
    some unused variables.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 149c0756b47bbf39a87545caabbb16866319871e
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Tue Dec 22 14:18:19 2015 +1300

    torture/gentest time_skew(): don't use labs() on unsigned NTTIME
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d098e9c4ba90f23589611efbe38c6f5ac4368e16
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Dec 21 16:40:28 2015 +1300

    repl: Skip new subdomains and partitions when replicating
    
    These will need to be handled later, but probably via reading the cross-ref objects.
    
    This avoids total failure when cloning a DC that has
    subdomains.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/netcmd/sites.py            | 163 ++++++++++--
 python/samba/sites.py                   |  52 ++--
 python/samba/subnets.py                 | 186 +++++++++++++
 python/samba/tests/samba_tool/sites.py  | 136 ++++++++++
 source4/dsdb/repl/replicated_objects.c  |  49 +++-
 source4/dsdb/samdb/ldb_modules/samldb.c | 279 ++++++++++++++++++++
 source4/dsdb/tests/python/sites.py      | 447 +++++++++++++++++++++++++++++---
 source4/selftest/tests.py               |   2 +
 source4/torture/gentest.c               |   7 +-
 9 files changed, 1236 insertions(+), 85 deletions(-)
 create mode 100644 python/samba/subnets.py
 create mode 100644 python/samba/tests/samba_tool/sites.py


Changeset truncated at 500 lines:

diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 09df55e..f0c792d 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -16,15 +16,15 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-import os
-from samba import sites
+from samba import sites, subnets
 from samba.samdb import SamDB
 import samba.getopt as options
 from samba.auth import system_session
 from samba.netcmd import (
     Command,
     CommandError,
-    SuperCommand
+    SuperCommand,
+    Option,
     )
 
 
@@ -41,26 +41,30 @@ class cmd_sites_create(Command):
         "credopts": options.CredentialsOptions,
     }
 
-    def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, sitename, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp, fallback_machine=True)
-        url =  lp.private_path("sam.ldb")
-
-        if not os.path.exists(url):
-            raise CommandError("secret database not found at %s " % url)
-        samdb = SamDB(url=url, session_info=system_session(),
+        samdb = SamDB(url=H, session_info=system_session(),
                       credentials=creds, lp=lp)
 
         samdb.transaction_start()
         try:
-            ok = sites.create_site(samdb, samdb.get_config_basedn(), sitename)
+            sites.create_site(samdb, samdb.get_config_basedn(), sitename)
             samdb.transaction_commit()
         except sites.SiteAlreadyExistsException, e:
             samdb.transaction_cancel()
-            raise CommandError("Error while creating site %s, error: %s" % (sitename, str(e)))
+            raise CommandError("Error while creating site %s, error: %s" %
+                               (sitename, str(e)))
 
         self.outf.write("Site %s created !\n" % sitename)
 
+
 class cmd_sites_delete(Command):
     """Delete an existing site."""
 
@@ -74,19 +78,21 @@ class cmd_sites_delete(Command):
         "credopts": options.CredentialsOptions,
     }
 
-    def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, sitename, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp, fallback_machine=True)
-        url =  lp.private_path("sam.ldb")
-
-        if not os.path.exists(url):
-            raise CommandError("secret database not found at %s " % url)
-        samdb = SamDB(url=url, session_info=system_session(),
-            credentials=creds, lp=lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
 
         samdb.transaction_start()
         try:
-            ok = sites.delete_site(samdb, samdb.get_config_basedn(), sitename)
+            sites.delete_site(samdb, samdb.get_config_basedn(), sitename)
             samdb.transaction_commit()
         except sites.SiteException, e:
             samdb.transaction_cancel()
@@ -96,10 +102,127 @@ class cmd_sites_delete(Command):
         self.outf.write("Site %s removed!\n" % sitename)
 
 
+class cmd_sites_subnet_create(Command):
+    """Create a new subnet."""
+    synopsis = "%prog <subnet> <site-of-subnet> [options]"
+    takes_args = ["subnetname", "site_of_subnet"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, site_of_subnet, H=None, sambaopts=None,
+            credopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.create_subnet(samdb, samdb.get_config_basedn(), subnetname,
+                                  site_of_subnet)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error while creating subnet %s: %s" %
+                               (subnetname, e))
+
+        self.outf.write("Subnet %s created !\n" % subnetname)
+
+
+class cmd_sites_subnet_delete(Command):
+    """Delete an existing subnet."""
+
+    synopsis = "%prog <subnet> [options]"
+
+    takes_args = ["subnetname"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, H=None, sambaopts=None, credopts=None,
+            versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.delete_subnet(samdb, samdb.get_config_basedn(), subnetname)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error while removing subnet %s, error: %s" %
+                               (subnetname, e))
+
+        self.outf.write("Subnet %s removed!\n" % subnetname)
+
+
+class cmd_sites_subnet_set_site(Command):
+    """Assign a subnet to a site."""
+    synopsis = "%prog <subnet> <site-of-subnet> [options]"
+    takes_args = ["subnetname", "site_of_subnet"]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    def run(self, subnetname, site_of_subnet, H=None, sambaopts=None,
+            credopts=None, versionopts=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        samdb.transaction_start()
+        try:
+            subnets.set_subnet_site(samdb, samdb.get_config_basedn(),
+                                    subnetname, site_of_subnet)
+            samdb.transaction_commit()
+        except subnets.SubnetException, e:
+            samdb.transaction_cancel()
+            raise CommandError("Error assigning subnet %s to site %s: %s" %
+                               (subnetname, site_of_subnet, e))
+
+        print >> self.outf, ("Subnet %s shifted to site %s" %
+                             (subnet_name, site_of_subnet))
+
+
+class cmd_sites_subnet(SuperCommand):
+    """Subnet management subcommands."""
+    subcommands = {
+        "create": cmd_sites_subnet_create(),
+        "remove": cmd_sites_subnet_delete(),
+        "set-site": cmd_sites_subnet_set_site(),
+    }
 
 class cmd_sites(SuperCommand):
     """Sites management."""
-
     subcommands = {}
     subcommands["create"] = cmd_sites_create()
     subcommands["remove"] = cmd_sites_delete()
+    subcommands["subnet"] = cmd_sites_subnet()
diff --git a/python/samba/sites.py b/python/samba/sites.py
index 76c57dd..7111cfa 100644
--- a/python/samba/sites.py
+++ b/python/samba/sites.py
@@ -18,7 +18,7 @@
 """Manipulating sites."""
 
 import ldb
-from ldb import FLAG_MOD_ADD
+from ldb import FLAG_MOD_ADD, LdbError
 
 
 class SiteException(Exception):
@@ -28,35 +28,20 @@ class SiteException(Exception):
         self.value = value
 
     def __str__(self):
-        return "SiteException: " + self.value
+        return "%s: %s" % (self.__class__.__name__, self.value)
 
 
 class SiteNotFoundException(SiteException):
     """Raised when the site is not found and it's expected to exists."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteNotFoundException: " + self.value
 
 class SiteAlreadyExistsException(SiteException):
     """Raised when the site is not found and it's expected not to exists."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteAlreadyExists: " + self.value
 
 class SiteServerNotEmptyException(SiteException):
     """Raised when the site still has servers attached."""
 
-    def __init__(self, value):
-        self.value = value
-
-    def __str__(self):
-        return "SiteServerNotEmpty: " + self.value
 
 def create_site(samdb, configDn, siteName):
     """
@@ -94,6 +79,7 @@ def create_site(samdb, configDn, siteName):
 
     return True
 
+
 def delete_site(samdb, configDn, siteName):
     """
     Delete a site
@@ -106,17 +92,27 @@ def delete_site(samdb, configDn, siteName):
     :raise SiteServerNotEmpty: if the site has still servers in it.
     """
 
-    dnsites = ldb.Dn(samdb, "CN=Sites,%s" % (str(configDn)))
-    dnsite = ldb.Dn(samdb, "Cn=%s,CN=Sites,%s" % (siteName, str(configDn)))
-    dnserver = ldb.Dn(samdb, "Cn=Servers,%s" % str(dnsite))
-
-    ret = samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
-                    expression='(dn=%s)' % str(dnsite))
-    if len(ret) != 1:
-        raise SiteNotFoundException('Site %s do not exists' % siteName)
-
-    ret = samdb.search(base=dnserver, scope=ldb.SCOPE_ONELEVEL,
-                    expression='(objectclass=server)')
+    dnsite = ldb.Dn(samdb, "CN=Sites")
+    if dnsite.add_base(configDn) == False:
+        raise SiteException("dnsites.add_base() failed")
+    if dnsite.add_child("CN=X") == False:
+        raise SiteException("dnsites.add_child() failed")
+    dnsite.set_component(0, "CN", siteName)
+
+    dnservers = ldb.Dn(samdb, "CN=Servers")
+    dnservers.add_base(dnsite)
+
+    try:
+        ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=site")
+        if len(ret) != 1:
+            raise SiteNotFoundException('Site %s does not exist' % siteName)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SiteNotFoundException('Site %s does not exist' % siteName)
+
+    ret = samdb.search(base=dnservers, scope=ldb.SCOPE_ONELEVEL,
+                       expression='(objectclass=server)')
     if len(ret) != 0:
         raise SiteServerNotEmptyException('Site %s still has servers in it, move them before removal' % siteName)
 
diff --git a/python/samba/subnets.py b/python/samba/subnets.py
new file mode 100644
index 0000000..e859f06
--- /dev/null
+++ b/python/samba/subnets.py
@@ -0,0 +1,186 @@
+# Add/remove subnets to sites.
+#
+# Copyright (C) Catalyst.Net Ltd 2015
+# Copyright Matthieu Patou <mat at matws.net> 2011
+#
+# Catalyst.Net's contribution was written by Douglas Bagnall
+# <douglas.bagnall at catalyst.net.nz>.
+#
+# 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/>.
+#
+
+import ldb
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, LdbError
+from sites import SiteNotFoundException
+
+class SubnetException(Exception):
+    """Base element for Subnet errors"""
+    pass
+
+
+class SubnetNotFound(SubnetException):
+    """The subnet requested does not exist."""
+    pass
+
+
+class SubnetAlreadyExists(SubnetException):
+    """The subnet being added already exists."""
+    pass
+
+
+class SubnetInvalid(SubnetException):
+    """The subnet CIDR is invalid."""
+    pass
+
+
+class SiteNotFound(SubnetException):
+    """The site to be used for the subnet does not exist."""
+    pass
+
+
+def create_subnet(samdb, configDn, subnet_name, site_name):
+    """Create a subnet and associate it with a site.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: name of the subnet to create (a CIDR range)
+    :return: None
+    :raise SubnetAlreadyExists: if the subnet to be created already exists.
+    :raise SiteNotFound: if the site does not exist.
+    """
+    ret = samdb.search(base=configDn, scope=ldb.SCOPE_SUBTREE,
+                       expression='(&(objectclass=Site)(cn=%s))' %
+                       ldb.binary_encode(site_name))
+    if len(ret) != 1:
+        raise SiteNotFound('A site with the name %s does not exist' %
+                           site_name)
+    dn_site = ret[0].dn
+
+    if not isinstance(subnet_name, str):
+        raise SubnetInvalid("%s is not a valid subnet (not a string)" % subnet_name)
+
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        m = ldb.Message()
+        m.dn = dnsubnet
+        m["objectclass"] = ldb.MessageElement("subnet", FLAG_MOD_ADD,
+                                              "objectclass")
+        m["siteObject"] = ldb.MessageElement(str(dn_site), FLAG_MOD_ADD,
+                                             "siteObject")
+        samdb.add(m)
+    except ldb.LdbError as (enum, estr):
+        if enum == ldb.ERR_INVALID_DN_SYNTAX:
+            raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name, estr))
+        elif enum == ldb.ERR_ENTRY_ALREADY_EXISTS:
+            # Subnet collisions are checked by exact match only, not
+            # overlapping range. This won't stop you creating
+            # 10.1.1.0/24 when there is already 10.1.0.0/16, or
+            # prevent you from having numerous IPv6 subnets that refer
+            # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
+            raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
+                                      % subnet_name)
+        else:
+            raise
+
+
+def delete_subnet(samdb, configDn, subnet_name):
+    """Delete a subnet.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: Name of the subnet to delete
+    :return: None
+    :raise SubnetNotFound: if the subnet to be deleted does not exist.
+    """
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=subnet")
+        if len(ret) != 1:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+
+    samdb.delete(dnsubnet)
+
+
+def set_subnet_site(samdb, configDn, subnet_name, site_name):
+    """Assign a subnet to a site.
+
+    This dissociates the subnet from its previous site.
+
+    :param samdb: A samdb connection
+    :param configDn: The DN of the configuration partition
+    :param subnet_name: Name of the subnet
+    :param site_name: Name of the site
+    :return: None
+    :raise SubnetNotFound: if the subnet does not exist.
+    :raise SiteNotFound: if the site does not exist.
+    """
+
+    dnsubnet = ldb.Dn(samdb, "CN=Subnets,CN=Sites")
+    if dnsubnet.add_base(configDn) == False:
+        raise SubnetException("dnsubnet.add_base() failed")
+    if dnsubnet.add_child("CN=X") == False:
+        raise SubnetException("dnsubnet.add_child() failed")
+    dnsubnet.set_component(0, "CN", subnet_name)
+
+    try:
+        ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=subnet")
+        if len(ret) != 1:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+    except LdbError as (enum, estr):
+        if enum == ldb.ERR_NO_SUCH_OBJECT:
+            raise SubnetNotFound('Subnet %s does not exist' % subnet_name)
+
+    dnsite = ldb.Dn(samdb, "CN=Sites")
+    if dnsite.add_base(configDn) == False:
+        raise SubnetException("dnsites.add_base() failed")
+    if dnsite.add_child("CN=X") == False:
+        raise SubnetException("dnsites.add_child() failed")
+    dnsite.set_component(0, "CN", site_name)
+
+    dnservers = ldb.Dn(samdb, "CN=Servers")
+    dnservers.add_base(dnsite)
+
+    try:
+        ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
+                           expression="objectClass=site")
+        if len(ret) != 1:
+            raise SiteNotFoundException('Site %s does not exist' % site_name)
+    except LdbError as (enum, estr):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list