1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00

netcmd: domain: add model exceptions and error handling

* Only handle what we know, otherwise raise the existing LdbError
* Cutom messages added in the model layer so we don't have to do it in
  the commands themselves

Signed-off-by: Rob van der Linde <rob@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
This commit is contained in:
Rob van der Linde 2023-06-23 12:24:24 +12:00 committed by Andrew Bartlett
parent b00761da1d
commit ca4e36d17a
3 changed files with 88 additions and 15 deletions

View File

@ -20,8 +20,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE, Message, MessageElement
from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE, LdbError, Message, MessageElement
from .exceptions import AddMemberError, RemoveMemberError
from .fields import DnField, BooleanField, StringField
from .model import Model
@ -65,7 +66,10 @@ class AuthenticationSilo(Model):
"msDS-AuthNPolicySiloMembers"))
# Update authentication silo.
ldb.modify(message)
try:
ldb.modify(message)
except LdbError as e:
raise AddMemberError(f"Failed to add silo member: {e}")
# If the modify operation was successful refresh members field.
self.refresh(ldb, fields=["members"])
@ -85,7 +89,10 @@ class AuthenticationSilo(Model):
"msDS-AuthNPolicySiloMembers"))
# Update authentication silo.
ldb.modify(message)
try:
ldb.modify(message)
except LdbError as e:
raise RemoveMemberError(f"Failed to remove silo member: {e}")
# If the modify operation was successful refresh members field.
self.refresh(ldb, fields=["members"])

View File

@ -20,5 +20,33 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
class MultipleObjectsReturned(Exception):
class ModelError(Exception):
pass
class MultipleObjectsReturned(ModelError):
pass
class DoesNotExist(ModelError):
pass
class AddMemberError(ModelError):
pass
class RemoveMemberError(ModelError):
pass
class ProtectError(ModelError):
pass
class UnprotectError(ModelError):
pass
class DeleteError(ModelError):
pass

View File

@ -27,7 +27,8 @@ from ldb import ERR_NO_SUCH_OBJECT, FLAG_MOD_ADD, FLAG_MOD_REPLACE, LdbError,\
Message, MessageElement, SCOPE_BASE, SCOPE_SUBTREE, binary_encode
from samba.sd_utils import SDUtils
from .exceptions import MultipleObjectsReturned
from .exceptions import DeleteError, DoesNotExist, MultipleObjectsReturned,\
ProtectError, UnprotectError
from .fields import DateTimeField, DnField, Field, GUIDField, IntegerField,\
StringField
@ -173,7 +174,15 @@ class Model(metaclass=ModelMeta):
:param fields: Optional list of field names to refresh
"""
attrs = [self.fields[f].name for f in fields] if fields else None
res = ldb.search(self.dn, scope=SCOPE_BASE, attrs=attrs)
# This shouldn't normally happen but in case the object refresh fails.
try:
res = ldb.search(self.dn, scope=SCOPE_BASE, attrs=attrs)
except LdbError as e:
if e.args[0] == ERR_NO_SUCH_OBJECT:
raise DoesNotExist(f"Refresh failed, object gone: {self.dn}")
raise
self._apply(ldb, res[0])
def as_dict(self, include_hidden=False):
@ -225,9 +234,17 @@ class Model(metaclass=ModelMeta):
:param ldb: Ldb connection
:param kwargs: Search criteria as keyword args
"""
result = ldb.search(cls.get_search_dn(ldb),
scope=SCOPE_SUBTREE,
expression=cls.build_expression(**kwargs))
base_dn = cls.get_search_dn(ldb)
# If the container does not exist produce a friendly error message.
try:
result = ldb.search(base_dn,
scope=SCOPE_SUBTREE,
expression=cls.build_expression(**kwargs))
except LdbError as e:
if e.args[0] == ERR_NO_SUCH_OBJECT:
raise DoesNotExist(f"Container does not exist: {base_dn}")
raise
# For now this returns a simple generator of model instances.
# This could eventually become a QuerySet class if we need to add
@ -262,9 +279,17 @@ class Model(metaclass=ModelMeta):
else:
raise
else:
res = ldb.search(cls.get_search_dn(ldb),
scope=SCOPE_SUBTREE,
expression=cls.build_expression(**kwargs))
base_dn = cls.get_search_dn(ldb)
# If the container does not exist produce a friendly error message.
try:
res = ldb.search(base_dn,
scope=SCOPE_SUBTREE,
expression=cls.build_expression(**kwargs))
except LdbError as e:
if e.args[0] == ERR_NO_SUCH_OBJECT:
raise DoesNotExist(f"Container does not exist: {base_dn}")
raise
# Expect to get one object back or raise MultipleObjectsReturned.
# For multiple records, please call .query() instead.
@ -382,8 +407,13 @@ class Model(metaclass=ModelMeta):
:param ldb: Ldb connection
"""
if self.dn is not None:
if self.dn is None:
raise DeleteError("Cannot delete object that doesn't have a dn.")
try:
ldb.delete(self.dn)
except LdbError as e:
raise DeleteError(f"Delete failed: {e}")
def protect(self, ldb):
"""Protect object from accidental deletion.
@ -391,7 +421,11 @@ class Model(metaclass=ModelMeta):
:param ldb: Ldb connection
"""
utils = SDUtils(ldb)
utils.dacl_add_ace(self.dn, "(D;;DTSD;;;WD)")
try:
utils.dacl_add_ace(self.dn, "(D;;DTSD;;;WD)")
except LdbError as e:
raise ProtectError(f"Failed to protect object: {e}")
def unprotect(self, ldb):
"""Unprotect object from accidental deletion.
@ -399,4 +433,8 @@ class Model(metaclass=ModelMeta):
:param ldb: Ldb connection
"""
utils = SDUtils(ldb)
utils.dacl_delete_aces(self.dn, "(D;;DTSD;;;WD)")
try:
utils.dacl_delete_aces(self.dn, "(D;;DTSD;;;WD)")
except LdbError as e:
raise UnprotectError(f"Failed to unprotect object: {e}")