[PATCH] samba-tool sites/subnets administration
Roel van Meer
roel at 1afa.com
Mon Jun 8 01:27:30 MDT 2015
Hi list,
attached are four patches that extend the functionality of samba-tool with
some commands for administration of sites and subnets. After these patches,
we have the following subcommands in the "samba-tool sites" command:
Available subcommands:
create - Create a new site.
createsubnet - Create a new subnet.
list - List all sites.
listsubnets - List all subnets.
moveserver - Move a server from one site to another.
remove - Delete an existing site.
removesubnet - Delete an existing subnet.
I've chosen to put the subnet subcommands under the sites command. Another
option would be to create a new supercommand "subnets". I can redo the
patches if that is preferred.
Things that are still missing are:
- There is not yet any input validation on the subnets. Do we already
have python code for network address validation somewhere?
- DNS entries aren't created and/or modified when changing sites.
Review and feedback would be appreciated.
Thanks,
Roel
-------------- next part --------------
>From 839565ada8c189e6045eac83b814fc835cd6b2f5 Mon Sep 17 00:00:00 2001
From: Roel van Meer <roel at 1afa.com>
Date: Thu, 4 Jun 2015 11:18:48 +0200
Subject: [PATCH 1/4] samba-tool sites: Add "list" command
This adds one command to samba-tool:
samba-tool sites list
The command lists the configured sites in the domain.
---
python/samba/netcmd/sites.py | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 09df55e..76c6f49 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -17,6 +17,7 @@
#
import os
+import ldb
from samba import sites
from samba.samdb import SamDB
import samba.getopt as options
@@ -95,6 +96,36 @@ class cmd_sites_delete(Command):
self.outf.write("Site %s removed!\n" % sitename)
+class cmd_sites_list(Command):
+ """List all sites."""
+
+ synopsis = "%prog [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ def run(self, 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)
+
+ res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE,
+ expression="(objectClass=Site)",
+ attrs=["cn"])
+ if (len(res) == 0):
+ return
+
+ for msg in res:
+ self.outf.write("%s\n" % msg.get("cn", idx=0))
+
class cmd_sites(SuperCommand):
@@ -103,3 +134,4 @@ class cmd_sites(SuperCommand):
subcommands = {}
subcommands["create"] = cmd_sites_create()
subcommands["remove"] = cmd_sites_delete()
+ subcommands["list"] = cmd_sites_list()
--
1.7.1
-------------- next part --------------
>From 9f7dcb8a428ea6baf8ecce11bd7ca34219ffd6df Mon Sep 17 00:00:00 2001
From: Roel van Meer <roel at 1afa.com>
Date: Thu, 4 Jun 2015 11:47:09 +0200
Subject: [PATCH 2/4] samba-tool sites: add -H option
This adds the -H option to the sites subcommands.
Note that the explicit check for existence of the database has been
removed, since none of the other modules have it.
---
python/samba/netcmd/sites.py | 43 +++++++++++++++++++++++++----------------
1 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 76c6f49..3ca3595 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -25,7 +25,8 @@ from samba.auth import system_session
from samba.netcmd import (
Command,
CommandError,
- SuperCommand
+ SuperCommand,
+ Option
)
@@ -36,20 +37,23 @@ class cmd_sites_create(Command):
takes_args = ["sitename"]
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
takes_optiongroups = {
"sambaopts": options.SambaOptions,
"versionopts": options.VersionOptions,
"credopts": options.CredentialsOptions,
}
- def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+ def run(self, sitename, sambaopts=None, credopts=None, versionopts=None,
+ H=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()
@@ -69,21 +73,24 @@ class cmd_sites_delete(Command):
takes_args = ["sitename"]
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
takes_optiongroups = {
"sambaopts": options.SambaOptions,
"versionopts": options.VersionOptions,
"credopts": options.CredentialsOptions,
}
- def run(self, sitename, sambaopts=None, credopts=None, versionopts=None):
+ def run(self, sitename, sambaopts=None, credopts=None, versionopts=None,
+ H=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:
@@ -101,20 +108,22 @@ class cmd_sites_list(Command):
synopsis = "%prog [options]"
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
takes_optiongroups = {
"sambaopts": options.SambaOptions,
"versionopts": options.VersionOptions,
"credopts": options.CredentialsOptions,
}
- def run(self, sambaopts=None, credopts=None, versionopts=None):
+ def run(self, sambaopts=None, credopts=None, versionopts=None, H=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)
res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE,
--
1.7.1
-------------- next part --------------
>From a20c19e08afb131851736b6d37e28cb0b9ac8959 Mon Sep 17 00:00:00 2001
From: Roel van Meer <roel at 1afa.com>
Date: Thu, 4 Jun 2015 15:57:00 +0200
Subject: [PATCH 3/4] samba-tool sites: Add "moveserver" command
This adds a command that can be used to move a server from one
site to another:
samba-tool sites moveserver <server> <current site> <new site>
---
python/samba/netcmd/sites.py | 39 ++++++++++++++++++
python/samba/sites.py | 92 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 128 insertions(+), 3 deletions(-)
diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 3ca3595..82b3ba6 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -135,6 +135,44 @@ class cmd_sites_list(Command):
for msg in res:
self.outf.write("%s\n" % msg.get("cn", idx=0))
+class cmd_sites_moveserver(Command):
+ """Move a server from one site to another."""
+
+ synopsis = "%prog <server> <current site> <new site> [options]"
+
+ takes_args = ["server", "cursitename", "newsitename"]
+
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ def run(self, server, cursitename, newsitename, sambaopts=None,
+ credopts=None, versionopts=None, H=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp, fallback_machine=True)
+
+ samdb = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ samdb.transaction_start()
+ try:
+ ok = sites.move_server(samdb, samdb.get_config_basedn(), server,
+ cursitename, newsitename)
+ samdb.transaction_commit()
+ except Exception, e:
+ samdb.transaction_cancel()
+ raise CommandError(
+ "Error while moving server %s, error: %s" % (server, str(e)))
+
+ self.outf.write("Server %s moved successfully\n" % server)
+
class cmd_sites(SuperCommand):
@@ -144,3 +182,4 @@ class cmd_sites(SuperCommand):
subcommands["create"] = cmd_sites_create()
subcommands["remove"] = cmd_sites_delete()
subcommands["list"] = cmd_sites_list()
+ subcommands["moveserver"] = cmd_sites_moveserver()
diff --git a/python/samba/sites.py b/python/samba/sites.py
index 76c57dd..6bcbdb5 100644
--- a/python/samba/sites.py
+++ b/python/samba/sites.py
@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Manipulating sites."""
+"""Manipulating sites and subnets."""
import ldb
from ldb import FLAG_MOD_ADD
@@ -32,7 +32,7 @@ class SiteException(Exception):
class SiteNotFoundException(SiteException):
- """Raised when the site is not found and it's expected to exists."""
+ """Raised when the site is not found and it's expected to exist."""
def __init__(self, value):
self.value = value
@@ -41,7 +41,7 @@ class SiteNotFoundException(SiteException):
return "SiteNotFoundException: " + self.value
class SiteAlreadyExistsException(SiteException):
- """Raised when the site is not found and it's expected not to exists."""
+ """Raised when the site is found and it's expected not to exist."""
def __init__(self, value):
self.value = value
@@ -58,6 +58,45 @@ class SiteServerNotEmptyException(SiteException):
def __str__(self):
return "SiteServerNotEmpty: " + self.value
+class ServerNotFoundException(SiteException):
+ """Raised when a server is not found and it's expected to exist."""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return "ServerNotFoundException: " + self.value
+
+
+class SubnetException(Exception):
+ """Base element for Subnet errors"""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return "SubnetException: " + self.value
+
+
+class SubnetNotFoundException(SubnetException):
+ """Raised when the site is not found and it's expected to exist."""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return "SubnetNotFoundException: " + self.value
+
+class SubnetAlreadyExistsException(SubnetException):
+ """Raised when the subnet is found and it's expected not to exist."""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return "SubnetAlreadyExists: " + self.value
+
+
def create_site(samdb, configDn, siteName):
"""
Create a site
@@ -123,3 +162,50 @@ def delete_site(samdb, configDn, siteName):
samdb.delete(dnsite, ["tree_delete:0"])
return True
+
+def move_server(samdb, configDn, server, cursiteName, newsiteName):
+ """
+ Move a server from one site to another
+
+ :param samdb: A samdb connection
+ :param configDn: The DN of the configuration partition
+ :param server: The name of the server to be moved
+ :param cursiteName: Name of the site the server is currently in
+ :param newsiteName: Name of the site the server should be moved to
+ :return: True upon success
+ :raise SiteNotFoundException: if either of the sites does not exist
+ :raise ServerNotFoundException: if the server is not found in the
+ specified site
+ """
+
+ dnsites = ldb.Dn(samdb, "CN=Sites,%s" % (str(configDn)))
+ dncursite = ldb.Dn(samdb, "CN=%s,CN=Sites,%s" %
+ (cursiteName, str(configDn)))
+ dnnewsite = ldb.Dn(samdb, "CN=%s,CN=Sites,%s" %
+ (newsiteName, str(configDn)))
+ dnservers = ldb.Dn(samdb, "CN=Servers,CN=%s,CN=Sites,%s" %
+ (cursiteName, str(configDn)))
+ dncurserver = ldb.Dn(samdb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" %
+ (server.upper(), cursiteName, str(configDn)))
+ dnnewserver = ldb.Dn(samdb, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" %
+ (server.upper(), newsiteName, str(configDn)))
+
+ ret = samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
+ expression='(dn=%s)' % str(dncursite))
+ if len(ret) != 1:
+ raise SiteNotFoundException('Site %s does not exist' % cursiteName)
+
+ ret = samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
+ expression='(dn=%s)' % str(dnnewsite))
+ if len(ret) != 1:
+ raise SiteNotFoundException('Site %s does not exist' % newsiteName)
+
+ ret = samdb.search(base=dnservers, scope=ldb.SCOPE_ONELEVEL,
+ expression='(dn=%s)' % str(dncurserver))
+ if len(ret) != 1:
+ raise ServerNotFoundException(
+ 'Server %s not found in site %s' % (server, cursiteName))
+
+ samdb.rename(dncurserver, dnnewserver)
+
+ return True
--
1.7.1
-------------- next part --------------
>From 370fe2cf87d1146629e3ec1e03944f9a2f25f374 Mon Sep 17 00:00:00 2001
From: Roel van Meer <roel at 1afa.com>
Date: Thu, 4 Jun 2015 16:07:03 +0200
Subject: [PATCH 4/4] samba-tool sites: Add commands for subnet administration
This adds three commands:
samba-tool sites listsubnets
samba-tool sites createsubnet <subnet>
samba-tool sites removesubnet <subnet>
---
python/samba/netcmd/sites.py | 110 ++++++++++++++++++++++++++++++++++++++++++
python/samba/sites.py | 60 +++++++++++++++++++++++
2 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/python/samba/netcmd/sites.py b/python/samba/netcmd/sites.py
index 82b3ba6..55dc7ea 100644
--- a/python/samba/netcmd/sites.py
+++ b/python/samba/netcmd/sites.py
@@ -173,6 +173,113 @@ class cmd_sites_moveserver(Command):
self.outf.write("Server %s moved successfully\n" % server)
+class cmd_sites_createsubnet(Command):
+ """Create a new subnet."""
+
+ synopsis = "%prog <subnet> <site> [options]"
+
+ takes_args = ["subnet", "sitename"]
+
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ def run(self, subnet, sitename, sambaopts=None, credopts=None,
+ versionopts=None, H=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp, fallback_machine=True)
+
+ samdb = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ samdb.transaction_start()
+ try:
+ ok = sites.create_subnet(samdb, samdb.get_config_basedn(),
+ subnet, sitename)
+ samdb.transaction_commit()
+ except Exception, e:
+ samdb.transaction_cancel()
+ raise CommandError(
+ "Error while creating subnet %s, error: %s" % (subnet, str(e)))
+
+ self.outf.write("Subnet %s created successfully\n" % subnet)
+
+class cmd_sites_deletesubnet(Command):
+ """Delete an existing subnet."""
+
+ synopsis = "%prog <subnet> [options]"
+
+ takes_args = ["subnet"]
+
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ def run(self, subnet, sambaopts=None, credopts=None, versionopts=None,
+ H=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp, fallback_machine=True)
+
+ samdb = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ samdb.transaction_start()
+ try:
+ ok = sites.delete_subnet(samdb, samdb.get_config_basedn(), subnet)
+ samdb.transaction_commit()
+ except Exception, e:
+ samdb.transaction_cancel()
+ raise CommandError(
+ "Error while removing subnet %s, error: %s" % (subnet, str(e)))
+
+ self.outf.write("Deleted subnet %s\n" % subnet)
+
+class cmd_sites_listsubnets(Command):
+ """List all subnets."""
+
+ synopsis = "%prog [options]"
+
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp, fallback_machine=True)
+
+ samdb = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE,
+ expression="(objectClass=Subnet)",
+ attrs=["cn"])
+ if (len(res) == 0):
+ return
+
+ for msg in res:
+ self.outf.write("%s\n" % msg.get("cn", idx=0))
+
class cmd_sites(SuperCommand):
@@ -183,3 +290,6 @@ class cmd_sites(SuperCommand):
subcommands["remove"] = cmd_sites_delete()
subcommands["list"] = cmd_sites_list()
subcommands["moveserver"] = cmd_sites_moveserver()
+ subcommands["listsubnets"] = cmd_sites_listsubnets()
+ subcommands["createsubnet"] = cmd_sites_createsubnet()
+ subcommands["removesubnet"] = cmd_sites_deletesubnet()
diff --git a/python/samba/sites.py b/python/samba/sites.py
index 6bcbdb5..8d6d1c9 100644
--- a/python/samba/sites.py
+++ b/python/samba/sites.py
@@ -209,3 +209,63 @@ def move_server(samdb, configDn, server, cursiteName, newsiteName):
samdb.rename(dncurserver, dnnewserver)
return True
+
+def create_subnet(samdb, configDn, subnet, siteName):
+ """
+ Create a subnet
+
+ :param samdb: A samdb connection
+ :param configDn: The DN of the configuration partition
+ :param subnet: The subnet to create
+ :param siteName: Name of the site to associate this subnet with
+ :return: True upon success
+ :raise SubnetAlreadyExists: if the subnet to be created already exists.
+ """
+
+ ret = samdb.search(base=configDn, scope=ldb.SCOPE_SUBTREE,
+ expression='(&(objectclass=Subnet)(cn=%s))' % subnet)
+ if len(ret) != 0:
+ raise SubnetAlreadyExistsException(
+ 'A subnet with the prefix %s already exists' % subnet)
+
+ dnsites = ldb.Dn(samdb, "CN=Sites,%s" % (str(configDn)))
+ dnsite = ldb.Dn(samdb, "CN=%s,CN=Sites,%s" % (siteName, str(configDn)))
+
+ ret = samdb.search(base=dnsites, scope=ldb.SCOPE_ONELEVEL,
+ expression='(dn=%s)' % str(dnsite))
+ if len(ret) != 1:
+ raise SiteNotFoundException('Site %s does not exist' % siteName)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, "CN=%s,CN=Subnets,CN=Sites,%s" %
+ (subnet, str(configDn)))
+ m["objectclass"] = ldb.MessageElement("subnet", FLAG_MOD_ADD, "objectclass")
+ m["siteObject"] = ("CN=%s,CN=Sites,%s" % (siteName, str(configDn)))
+
+ samdb.add(m)
+
+ return True
+
+def delete_subnet(samdb, configDn, subnet):
+ """
+ Delete a subnet
+
+ :param samdb: A samdb connection
+ :param configDn: The DN of the configuration partition
+ :param subnet: The subnet to delete
+ :return: True upon success
+ :raise SubnetNotFoundException: if the site to be deleted does not exist.
+ """
+
+ dnsubnets = ldb.Dn(samdb, "CN=Subnets,CN=Sites,%s" % (str(configDn)))
+ dnsubnet = ldb.Dn(samdb, "CN=%s,CN=Subnets,CN=Sites,%s" %
+ (subnet, str(configDn)))
+
+ ret = samdb.search(base=dnsubnets, scope=ldb.SCOPE_ONELEVEL,
+ expression='(dn=%s)' % str(dnsubnet))
+ if len(ret) != 1:
+ raise SubnetNotFoundException('Subnet %s does not exist' % subnet)
+
+ samdb.delete(dnsubnet, ["tree_delete:0"])
+
+ return True
--
1.7.1
More information about the samba-technical
mailing list