summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRob van der Linde <rob@catalyst.net.nz>2023-03-31 13:34:20 +1300
committerAndrew Bartlett <abartlet@samba.org>2023-03-31 07:25:32 +0000
commit75e7935b503308458442cf0ef46899b04cea40c5 (patch)
treedf48803229bfd652f7b2ad1b28c9f46ff9ec08be /python
parentdff87f051f180a48fad9d12039622c6df9396f2c (diff)
downloadsamba-75e7935b503308458442cf0ef46899b04cea40c5.tar.gz
netcmd: domain: move schemaupgrade command to domain/schemaupgrade.py
Signed-off-by: Rob van der Linde <rob@catalyst.net.nz> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'python')
-rw-r--r--python/samba/netcmd/domain/__init__.py322
-rw-r--r--python/samba/netcmd/domain/schemaupgrade.py350
2 files changed, 351 insertions, 321 deletions
diff --git a/python/samba/netcmd/domain/__init__.py b/python/samba/netcmd/domain/__init__.py
index 6b0383a756f..19ef1b05c42 100644
--- a/python/samba/netcmd/domain/__init__.py
+++ b/python/samba/netcmd/domain/__init__.py
@@ -24,12 +24,8 @@
import samba.getopt as options
import ldb
-import os
import ctypes
-import tempfile
-import subprocess
import time
-import shutil
from samba import ntstatus
from samba import NTSTATUSError
from samba import werror
@@ -49,12 +45,9 @@ from samba.netcmd import (
SuperCommand,
Option
)
-from samba.netcmd.fsmo import get_fsmo_roleowner
from samba import string_to_byte_array
from samba import is_ad_dc_built
-from samba.provision import setup_path
-
from samba.trust_utils import CreateTrustedDomainRelax
from .backup import cmd_domain_backup
@@ -72,6 +65,7 @@ from .level import cmd_domain_level
from .passwordsettings import cmd_domain_passwordsettings
from .provision import cmd_domain_provision
from .samba3upgrade import cmd_domain_samba3upgrade
+from .schemaupgrade import cmd_domain_schema_upgrade
class LocalDCCredentialsOptions(options.CredentialsOptions):
@@ -2459,320 +2453,6 @@ class cmd_domain_tombstones(SuperCommand):
subcommands["expunge"] = cmd_domain_tombstones_expunge()
-class ldif_schema_update:
- """Helper class for applying LDIF schema updates"""
-
- def __init__(self):
- self.is_defunct = False
- self.unknown_oid = None
- self.dn = None
- self.ldif = ""
-
- def can_ignore_failure(self, error):
- """Checks if we can safely ignore failure to apply an LDIF update"""
- (num, errstr) = error.args
-
- # Microsoft has marked objects as defunct that Samba doesn't know about
- if num == ldb.ERR_NO_SUCH_OBJECT and self.is_defunct:
- print("Defunct object %s doesn't exist, skipping" % self.dn)
- return True
- elif self.unknown_oid is not None:
- print("Skipping unknown OID %s for object %s" % (self.unknown_oid, self.dn))
- return True
-
- return False
-
- def apply(self, samdb):
- """Applies a single LDIF update to the schema"""
-
- try:
- try:
- samdb.modify_ldif(self.ldif, controls=['relax:0'])
- except ldb.LdbError as e:
- if e.args[0] == ldb.ERR_INVALID_ATTRIBUTE_SYNTAX:
-
- # REFRESH after a failed change
-
- # Otherwise the OID-to-attribute mapping in
- # _apply_updates_in_file() won't work, because it
- # can't lookup the new OID in the schema
- samdb.set_schema_update_now()
-
- samdb.modify_ldif(self.ldif, controls=['relax:0'])
- else:
- raise
- except ldb.LdbError as e:
- if self.can_ignore_failure(e):
- return 0
- else:
- print("Exception: %s" % e)
- print("Encountered while trying to apply the following LDIF")
- print("----------------------------------------------------")
- print("%s" % self.ldif)
-
- raise
-
- return 1
-
-
-class cmd_domain_schema_upgrade(Command):
- """Domain schema upgrading"""
-
- synopsis = "%prog [options]"
-
- 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"),
- Option("-q", "--quiet", help="Be quiet", action="store_true"), # unused
- Option("-v", "--verbose", help="Be verbose", action="store_true"),
- Option("--schema", type="choice", metavar="SCHEMA",
- choices=["2012", "2012_R2", "2016", "2019"],
- help="The schema file to upgrade to. Default is (Windows) 2019.",
- default="2019"),
- Option("--ldf-file", type=str, default=None,
- help="Just apply the schema updates in the adprep/.LDF file(s) specified"),
- Option("--base-dir", type=str, default=None,
- help="Location of ldf files Default is ${SETUPDIR}/adprep.")
- ]
-
- def _apply_updates_in_file(self, samdb, ldif_file):
- """
- Applies a series of updates specified in an .LDIF file. The .LDIF file
- is based on the adprep Schema updates provided by Microsoft.
- """
- count = 0
- ldif_op = ldif_schema_update()
-
- # parse the file line by line and work out each update operation to apply
- for line in ldif_file:
-
- line = line.rstrip()
-
- # the operations in the .LDIF file are separated by blank lines. If
- # we hit a blank line, try to apply the update we've parsed so far
- if line == '':
-
- # keep going if we haven't parsed anything yet
- if ldif_op.ldif == '':
- continue
-
- # Apply the individual change
- count += ldif_op.apply(samdb)
-
- # start storing the next operation from scratch again
- ldif_op = ldif_schema_update()
- continue
-
- # replace the placeholder domain name in the .ldif file with the real domain
- if line.upper().endswith('DC=X'):
- line = line[:-len('DC=X')] + str(samdb.get_default_basedn())
- elif line.upper().endswith('CN=X'):
- line = line[:-len('CN=X')] + str(samdb.get_default_basedn())
-
- values = line.split(':')
-
- if values[0].lower() == 'dn':
- ldif_op.dn = values[1].strip()
-
- # replace the Windows-specific operation with the Samba one
- if values[0].lower() == 'changetype':
- line = line.lower().replace(': ntdsschemaadd',
- ': add')
- line = line.lower().replace(': ntdsschemamodify',
- ': modify')
- line = line.lower().replace(': ntdsschemamodrdn',
- ': modrdn')
- line = line.lower().replace(': ntdsschemadelete',
- ': delete')
-
- if values[0].lower() in ['rdnattid', 'subclassof',
- 'systemposssuperiors',
- 'systemmaycontain',
- 'systemauxiliaryclass']:
- _, value = values
-
- # The Microsoft updates contain some OIDs we don't recognize.
- # Query the DB to see if we can work out the OID this update is
- # referring to. If we find a match, then replace the OID with
- # the ldapDisplayname
- if '.' in value:
- res = samdb.search(base=samdb.get_schema_basedn(),
- expression="(|(attributeId=%s)(governsId=%s))" %
- (value, value),
- attrs=['ldapDisplayName'])
-
- if len(res) != 1:
- ldif_op.unknown_oid = value
- else:
- display_name = str(res[0]['ldapDisplayName'][0])
- line = line.replace(value, ' ' + display_name)
-
- # Microsoft has marked objects as defunct that Samba doesn't know about
- if values[0].lower() == 'isdefunct' and values[1].strip().lower() == 'true':
- ldif_op.is_defunct = True
-
- # Samba has added the showInAdvancedViewOnly attribute to all objects,
- # so rather than doing an add, we need to do a replace
- if values[0].lower() == 'add' and values[1].strip().lower() == 'showinadvancedviewonly':
- line = 'replace: showInAdvancedViewOnly'
-
- # Add the line to the current LDIF operation (including the newline
- # we stripped off at the start of the loop)
- ldif_op.ldif += line + '\n'
-
- return count
-
- def _apply_update(self, samdb, update_file, base_dir):
- """Wrapper function for parsing an LDIF file and applying the updates"""
-
- print("Applying %s updates..." % update_file)
-
- ldif_file = None
- try:
- ldif_file = open(os.path.join(base_dir, update_file))
-
- count = self._apply_updates_in_file(samdb, ldif_file)
-
- finally:
- if ldif_file:
- ldif_file.close()
-
- print("%u changes applied" % count)
-
- return count
-
- def run(self, **kwargs):
- try:
- from samba.ms_schema_markdown import read_ms_markdown
- except ImportError as e:
- self.outf.write("Exception in importing markdown: %s" % e)
- raise CommandError('Failed to import module markdown')
- from samba.schema import Schema
-
- updates_allowed_overridden = False
- sambaopts = kwargs.get("sambaopts")
- credopts = kwargs.get("credopts")
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- H = kwargs.get("H")
- target_schema = kwargs.get("schema")
- ldf_files = kwargs.get("ldf_file")
- base_dir = kwargs.get("base_dir")
-
- temp_folder = None
-
- samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp)
-
- # we're not going to get far if the config doesn't allow schema updates
- if lp.get("dsdb:schema update allowed") is None:
- lp.set("dsdb:schema update allowed", "yes")
- print("Temporarily overriding 'dsdb:schema update allowed' setting")
- updates_allowed_overridden = True
-
- own_dn = ldb.Dn(samdb, samdb.get_dsServiceName())
- master = get_fsmo_roleowner(samdb, str(samdb.get_schema_basedn()),
- 'schema')
- if own_dn != master:
- raise CommandError("This server is not the schema master.")
-
- # if specific LDIF files were specified, just apply them
- if ldf_files:
- schema_updates = ldf_files.split(",")
- else:
- schema_updates = []
-
- # work out the version of the target schema we're upgrading to
- end = Schema.get_version(target_schema)
-
- # work out the version of the schema we're currently using
- res = samdb.search(base=samdb.get_schema_basedn(),
- scope=ldb.SCOPE_BASE, attrs=['objectVersion'])
-
- if len(res) != 1:
- raise CommandError('Could not determine current schema version')
- start = int(res[0]['objectVersion'][0]) + 1
-
- diff_dir = setup_path("adprep/WindowsServerDocs")
- if base_dir is None:
- # Read from the Schema-Updates.md file
- temp_folder = tempfile.mkdtemp()
-
- update_file = setup_path("adprep/WindowsServerDocs/Schema-Updates.md")
-
- try:
- read_ms_markdown(update_file, temp_folder)
- except Exception as e:
- print("Exception in markdown parsing: %s" % e)
- shutil.rmtree(temp_folder)
- raise CommandError('Failed to upgrade schema')
-
- base_dir = temp_folder
-
- for version in range(start, end + 1):
- update = 'Sch%d.ldf' % version
- schema_updates.append(update)
-
- # Apply patches if we parsed the Schema-Updates.md file
- diff = os.path.abspath(os.path.join(diff_dir, update + '.diff'))
- if temp_folder and os.path.exists(diff):
- try:
- p = subprocess.Popen(['patch', update, '-i', diff],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, cwd=temp_folder)
- except (OSError, IOError):
- shutil.rmtree(temp_folder)
- raise CommandError("Failed to upgrade schema. "
- "Is '/usr/bin/patch' missing?")
-
- stdout, stderr = p.communicate()
-
- if p.returncode:
- print("Exception in patch: %s\n%s" % (stdout, stderr))
- shutil.rmtree(temp_folder)
- raise CommandError('Failed to upgrade schema')
-
- print("Patched %s using %s" % (update, diff))
-
- if base_dir is None:
- base_dir = setup_path("adprep")
-
- samdb.transaction_start()
- count = 0
- error_encountered = False
-
- try:
- # Apply the schema updates needed to move to the new schema version
- for ldif_file in schema_updates:
- count += self._apply_update(samdb, ldif_file, base_dir)
-
- if count > 0:
- samdb.transaction_commit()
- print("Schema successfully updated")
- else:
- print("No changes applied to schema")
- samdb.transaction_cancel()
- except Exception as e:
- print("Exception: %s" % e)
- print("Error encountered, aborting schema upgrade")
- samdb.transaction_cancel()
- error_encountered = True
-
- if updates_allowed_overridden:
- lp.set("dsdb:schema update allowed", "no")
-
- if temp_folder:
- shutil.rmtree(temp_folder)
-
- if error_encountered:
- raise CommandError('Failed to upgrade schema')
-
-
class cmd_domain(SuperCommand):
"""Domain management."""
diff --git a/python/samba/netcmd/domain/schemaupgrade.py b/python/samba/netcmd/domain/schemaupgrade.py
new file mode 100644
index 00000000000..1d67ab58c15
--- /dev/null
+++ b/python/samba/netcmd/domain/schemaupgrade.py
@@ -0,0 +1,350 @@
+# domain management - domain schemaupgrade
+#
+# Copyright Matthias Dieter Wallnoefer 2009
+# Copyright Andrew Kroeger 2009
+# Copyright Jelmer Vernooij 2007-2012
+# Copyright Giampaolo Lauria 2011
+# Copyright Matthieu Patou <mat@matws.net> 2011
+# Copyright Andrew Bartlett 2008-2015
+# Copyright Stefan Metzmacher 2012
+#
+# 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 os
+import shutil
+import subprocess
+import tempfile
+
+import ldb
+import samba.getopt as options
+from samba.auth import system_session
+from samba.netcmd import Command, CommandError, Option
+from samba.netcmd.fsmo import get_fsmo_roleowner
+from samba.provision import setup_path
+from samba.samdb import SamDB
+
+
+class ldif_schema_update:
+ """Helper class for applying LDIF schema updates"""
+
+ def __init__(self):
+ self.is_defunct = False
+ self.unknown_oid = None
+ self.dn = None
+ self.ldif = ""
+
+ def can_ignore_failure(self, error):
+ """Checks if we can safely ignore failure to apply an LDIF update"""
+ (num, errstr) = error.args
+
+ # Microsoft has marked objects as defunct that Samba doesn't know about
+ if num == ldb.ERR_NO_SUCH_OBJECT and self.is_defunct:
+ print("Defunct object %s doesn't exist, skipping" % self.dn)
+ return True
+ elif self.unknown_oid is not None:
+ print("Skipping unknown OID %s for object %s" % (self.unknown_oid, self.dn))
+ return True
+
+ return False
+
+ def apply(self, samdb):
+ """Applies a single LDIF update to the schema"""
+
+ try:
+ try:
+ samdb.modify_ldif(self.ldif, controls=['relax:0'])
+ except ldb.LdbError as e:
+ if e.args[0] == ldb.ERR_INVALID_ATTRIBUTE_SYNTAX:
+
+ # REFRESH after a failed change
+
+ # Otherwise the OID-to-attribute mapping in
+ # _apply_updates_in_file() won't work, because it
+ # can't lookup the new OID in the schema
+ samdb.set_schema_update_now()
+
+ samdb.modify_ldif(self.ldif, controls=['relax:0'])
+ else:
+ raise
+ except ldb.LdbError as e:
+ if self.can_ignore_failure(e):
+ return 0
+ else:
+ print("Exception: %s" % e)
+ print("Encountered while trying to apply the following LDIF")
+ print("----------------------------------------------------")
+ print("%s" % self.ldif)
+
+ raise
+
+ return 1
+
+
+class cmd_domain_schema_upgrade(Command):
+ """Domain schema upgrading"""
+
+ synopsis = "%prog [options]"
+
+ 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"),
+ Option("-q", "--quiet", help="Be quiet", action="store_true"), # unused
+ Option("-v", "--verbose", help="Be verbose", action="store_true"),
+ Option("--schema", type="choice", metavar="SCHEMA",
+ choices=["2012", "2012_R2", "2016", "2019"],
+ help="The schema file to upgrade to. Default is (Windows) 2019.",
+ default="2019"),
+ Option("--ldf-file", type=str, default=None,
+ help="Just apply the schema updates in the adprep/.LDF file(s) specified"),
+ Option("--base-dir", type=str, default=None,
+ help="Location of ldf files Default is ${SETUPDIR}/adprep.")
+ ]
+
+ def _apply_updates_in_file(self, samdb, ldif_file):
+ """
+ Applies a series of updates specified in an .LDIF file. The .LDIF file
+ is based on the adprep Schema updates provided by Microsoft.
+ """
+ count = 0
+ ldif_op = ldif_schema_update()
+
+ # parse the file line by line and work out each update operation to apply
+ for line in ldif_file:
+
+ line = line.rstrip()
+
+ # the operations in the .LDIF file are separated by blank lines. If
+ # we hit a blank line, try to apply the update we've parsed so far
+ if line == '':
+
+ # keep going if we haven't parsed anything yet
+ if ldif_op.ldif == '':
+ continue
+
+ # Apply the individual change
+ count += ldif_op.apply(samdb)
+
+ # start storing the next operation from scratch again
+ ldif_op = ldif_schema_update()
+ continue
+
+ # replace the placeholder domain name in the .ldif file with the real domain
+ if line.upper().endswith('DC=X'):
+ line = line[:-len('DC=X')] + str(samdb.get_default_basedn())
+ elif line.upper().endswith('CN=X'):
+ line = line[:-len('CN=X')] + str(samdb.get_default_basedn())
+
+ values = line.split(':')
+
+ if values[0].lower() == 'dn':
+ ldif_op.dn = values[1].strip()
+
+ # replace the Windows-specific operation with the Samba one
+ if values[0].lower() == 'changetype':
+ line = line.lower().replace(': ntdsschemaadd',
+ ': add')
+ line = line.lower().replace(': ntdsschemamodify',
+ ': modify')
+ line = line.lower().replace(': ntdsschemamodrdn',
+ ': modrdn')
+ line = line.lower().replace(': ntdsschemadelete',
+ ': delete')
+
+ if values[0].lower() in ['rdnattid', 'subclassof',
+ 'systemposssuperiors',
+ 'systemmaycontain',
+ 'systemauxiliaryclass']:
+ _, value = values
+
+ # The Microsoft updates contain some OIDs we don't recognize.
+ # Query the DB to see if we can work out the OID this update is
+ # referring to. If we find a match, then replace the OID with
+ # the ldapDisplayname
+ if '.' in value:
+ res = samdb.search(base=samdb.get_schema_basedn(),
+ expression="(|(attributeId=%s)(governsId=%s))" %
+ (value, value),
+ attrs=['ldapDisplayName'])
+
+ if len(res) != 1:
+ ldif_op.unknown_oid = value
+ else:
+ display_name = str(res[0]['ldapDisplayName'][0])
+ line = line.replace(value, ' ' + display_name)
+
+ # Microsoft has marked objects as defunct that Samba doesn't know about
+ if values[0].lower() == 'isdefunct' and values[1].strip().lower() == 'true':
+ ldif_op.is_defunct = True
+
+ # Samba has added the showInAdvancedViewOnly attribute to all objects,
+ # so rather than doing an add, we need to do a replace
+ if values[0].lower() == 'add' and values[1].strip().lower() == 'showinadvancedviewonly':
+ line = 'replace: showInAdvancedViewOnly'
+
+ # Add the line to the current LDIF operation (including the newline
+ # we stripped off at the start of the loop)
+ ldif_op.ldif += line + '\n'
+
+ return count
+
+ def _apply_update(self, samdb, update_file, base_dir):
+ """Wrapper function for parsing an LDIF file and applying the updates"""
+
+ print("Applying %s updates..." % update_file)
+
+ ldif_file = None
+ try:
+ ldif_file = open(os.path.join(base_dir, update_file))
+
+ count = self._apply_updates_in_file(samdb, ldif_file)
+
+ finally:
+ if ldif_file:
+ ldif_file.close()
+
+ print("%u changes applied" % count)
+
+ return count
+
+ def run(self, **kwargs):
+ try:
+ from samba.ms_schema_markdown import read_ms_markdown
+ except ImportError as e:
+ self.outf.write("Exception in importing markdown: %s" % e)
+ raise CommandError('Failed to import module markdown')
+ from samba.schema import Schema
+
+ updates_allowed_overridden = False
+ sambaopts = kwargs.get("sambaopts")
+ credopts = kwargs.get("credopts")
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+ H = kwargs.get("H")
+ target_schema = kwargs.get("schema")
+ ldf_files = kwargs.get("ldf_file")
+ base_dir = kwargs.get("base_dir")
+
+ temp_folder = None
+
+ samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp)
+
+ # we're not going to get far if the config doesn't allow schema updates
+ if lp.get("dsdb:schema update allowed") is None:
+ lp.set("dsdb:schema update allowed", "yes")
+ print("Temporarily overriding 'dsdb:schema update allowed' setting")
+ updates_allowed_overridden = True
+
+ own_dn = ldb.Dn(samdb, samdb.get_dsServiceName())
+ master = get_fsmo_roleowner(samdb, str(samdb.get_schema_basedn()),
+ 'schema')
+ if own_dn != master:
+ raise CommandError("This server is not the schema master.")
+
+ # if specific LDIF files were specified, just apply them
+ if ldf_files:
+ schema_updates = ldf_files.split(",")
+ else:
+ schema_updates = []
+
+ # work out the version of the target schema we're upgrading to
+ end = Schema.get_version(target_schema)
+
+ # work out the version of the schema we're currently using
+ res = samdb.search(base=samdb.get_schema_basedn(),
+ scope=ldb.SCOPE_BASE, attrs=['objectVersion'])
+
+ if len(res) != 1:
+ raise CommandError('Could not determine current schema version')
+ start = int(res[0]['objectVersion'][0]) + 1
+
+ diff_dir = setup_path("adprep/WindowsServerDocs")
+ if base_dir is None:
+ # Read from the Schema-Updates.md file
+ temp_folder = tempfile.mkdtemp()
+
+ update_file = setup_path("adprep/WindowsServerDocs/Schema-Updates.md")
+
+ try:
+ read_ms_markdown(update_file, temp_folder)
+ except Exception as e:
+ print("Exception in markdown parsing: %s" % e)
+ shutil.rmtree(temp_folder)
+ raise CommandError('Failed to upgrade schema')
+
+ base_dir = temp_folder
+
+ for version in range(start, end + 1):
+ update = 'Sch%d.ldf' % version
+ schema_updates.append(update)
+
+ # Apply patches if we parsed the Schema-Updates.md file
+ diff = os.path.abspath(os.path.join(diff_dir, update + '.diff'))
+ if temp_folder and os.path.exists(diff):
+ try:
+ p = subprocess.Popen(['patch', update, '-i', diff],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, cwd=temp_folder)
+ except (OSError, IOError):
+ shutil.rmtree(temp_folder)
+ raise CommandError("Failed to upgrade schema. "
+ "Is '/usr/bin/patch' missing?")
+
+ stdout, stderr = p.communicate()
+
+ if p.returncode:
+ print("Exception in patch: %s\n%s" % (stdout, stderr))
+ shutil.rmtree(temp_folder)
+ raise CommandError('Failed to upgrade schema')
+
+ print("Patched %s using %s" % (update, diff))
+
+ if base_dir is None:
+ base_dir = setup_path("adprep")
+
+ samdb.transaction_start()
+ count = 0
+ error_encountered = False
+
+ try:
+ # Apply the schema updates needed to move to the new schema version
+ for ldif_file in schema_updates:
+ count += self._apply_update(samdb, ldif_file, base_dir)
+
+ if count > 0:
+ samdb.transaction_commit()
+ print("Schema successfully updated")
+ else:
+ print("No changes applied to schema")
+ samdb.transaction_cancel()
+ except Exception as e:
+ print("Exception: %s" % e)
+ print("Error encountered, aborting schema upgrade")
+ samdb.transaction_cancel()
+ error_encountered = True
+
+ if updates_allowed_overridden:
+ lp.set("dsdb:schema update allowed", "no")
+
+ if temp_folder:
+ shutil.rmtree(temp_folder)
+
+ if error_encountered:
+ raise CommandError('Failed to upgrade schema')