forked from shaba/openuds
Refactoring, to make things easier to understand and use
This commit is contained in:
parent
bef6a52354
commit
713614a784
@ -53,6 +53,7 @@ encoding//src/uds/core/managers/UserPrefsManager.py=utf-8
|
||||
encoding//src/uds/core/managers/UserServiceManager.py=utf-8
|
||||
encoding//src/uds/core/osmanagers/BaseOsManager.py=utf-8
|
||||
encoding//src/uds/core/osmanagers/OSManagersFactory.py=utf-8
|
||||
encoding//src/uds/core/osmanagers/__init__.py=utf-8
|
||||
encoding//src/uds/core/services/BaseDeployed.py=utf-8
|
||||
encoding//src/uds/core/services/BasePublication.py=utf-8
|
||||
encoding//src/uds/core/services/BaseService.py=utf-8
|
||||
@ -96,8 +97,6 @@ encoding//src/uds/migrations/0005_auto__add_field_config_crypt.py=utf-8
|
||||
encoding//src/uds/models.py=utf-8
|
||||
encoding//src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/LinuxOsManager/__init__.py=utf-8
|
||||
encoding//src/uds/osmanagers/NoneOsManager/Manager.py=utf-8
|
||||
encoding//src/uds/osmanagers/NoneOsManager/__init__.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/WinDomainOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py=utf-8
|
||||
encoding//src/uds/osmanagers/WindowsOsManager/__init__.py=utf-8
|
||||
|
@ -30,16 +30,6 @@
|
||||
'''
|
||||
UDS authentication related interfaces and classes
|
||||
|
||||
From 1.0 onwards, the refactoring of UDS has started.
|
||||
|
||||
We can access the base service interfaces the old method, or recommended
|
||||
and easier use the new one, that is "from uds.core.services import ..."
|
||||
|
||||
The new valid names for classes are:
|
||||
|
||||
|
||||
I think this is an easier to use and understand way of accessing this classes
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from BaseAuthenticator import Authenticator
|
||||
|
@ -37,7 +37,7 @@ from uds.core import Module
|
||||
|
||||
STORAGE_KEY = 'osmk'
|
||||
|
||||
class BaseOSManager(Module):
|
||||
class OSManager(Module):
|
||||
'''
|
||||
An OS Manager is responsible for communication the service the different actions to take (i.e. adding a windows machine to a domain)
|
||||
The Service (i.e. virtual machine) communicates with the OSManager via a published web method, that must include the unique ID.
|
||||
@ -56,7 +56,7 @@ class BaseOSManager(Module):
|
||||
processUnusedMachines = False
|
||||
|
||||
def __init__(self,environment, values):
|
||||
super(BaseOSManager, self).__init__(environment, values)
|
||||
super(OSManager, self).__init__(environment, values)
|
||||
self.initialize(values)
|
||||
|
||||
def initialize(self, values):
|
||||
|
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
UDS os managers related interfaces and classes
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from BaseOsManager import OSManager
|
||||
|
||||
def factory():
|
||||
'''
|
||||
Returns factory for register/access to authenticators
|
||||
'''
|
||||
from OSManagersFactory import OSManagersFactory
|
||||
return OSManagersFactory.factory()
|
||||
|
@ -124,7 +124,7 @@ class UserDeployment(Environmentable, Serializable):
|
||||
kwargs: List of arguments that will receive:
|
||||
service: Parent service (derived from Service) of this deployment (this is an instance, not database object)
|
||||
publication: Parent publication (derived from Publication) of this deployment (optional)(this is an instance, not database object)
|
||||
osmanager: Parent osmanager (derived from BaseOsManager) of this deployment (optional)(this is an instance, not database object)
|
||||
osmanager: Parent osmanager (derived from :py:class:`uds.core.osmanagersOSManager`) of this deployment (optional)(this is an instance, not database object)
|
||||
dbservice: Database object for this service
|
||||
'''
|
||||
Environmentable.__init__(self, environment)
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import signals
|
||||
from uds.core.osmanagers.OSManagersFactory import OSManagersFactory
|
||||
from uds.core.jobs.JobsFactory import JobsFactory
|
||||
from uds.core.Environment import Environment
|
||||
from uds.core.util.db.LockingManager import LockingManager
|
||||
@ -296,8 +295,9 @@ class OSManager(models.Model):
|
||||
|
||||
:note: We only need to get info from this, not access specific data (class specific info)
|
||||
'''
|
||||
# We only need to get info from this, not access specific data (class specific info
|
||||
return OSManagersFactory.factory().lookup(self.data_type)
|
||||
# We only need to get info from this, not access specific data (class specific info)
|
||||
from uds.core import osmanagers
|
||||
return osmanagers.factory().lookup(self.data_type)
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -33,14 +33,15 @@
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.osmanagers.BaseOsManager import BaseOSManager, State
|
||||
from uds.core import osmanagers
|
||||
from uds.core.util.State import State
|
||||
|
||||
import logging
|
||||
from uds.core.managers.UserServiceManager import UserServiceManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class LinuxOsManager(BaseOSManager):
|
||||
class LinuxOsManager(osmanagers.OSManager):
|
||||
typeName = _('Linux OS Manager')
|
||||
typeType = 'LinuxManager'
|
||||
typeDescription = _('Os Manager to control linux virtual machines (basically renames machine and notify state)')
|
||||
|
@ -1,72 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.osmanagers.BaseOsManager import BaseOSManager, State
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class NoneOSManager(BaseOSManager):
|
||||
typeName = _('None OS Manager')
|
||||
typeType = 'NoneOSManager'
|
||||
typeDescription = _('Os Manager with no actions')
|
||||
iconFile = 'osmanager.png'
|
||||
|
||||
def __init__(self,environment, values):
|
||||
super(NoneOSManager, self).__init__(environment, values)
|
||||
|
||||
def process(self,service,msg, data):
|
||||
logger.info("Invoked NoneOsManager for {0} with params: {1}, {2}".format(service, msg, data))
|
||||
return "noneos"
|
||||
|
||||
def checkState(self,service):
|
||||
logger.debug('Checking state for service {0}'.format(service))
|
||||
return State.FINISHED
|
||||
|
||||
def marshal(self):
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
return str.join( '\t', [ 'v1' ] )
|
||||
|
||||
def unmarshal(self, str):
|
||||
data = str.split('\t')
|
||||
if data[0] == 'v1':
|
||||
pass
|
||||
|
||||
def valuesDict(self):
|
||||
return {}
|
||||
|
@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.osmanagers.OSManagersFactory import OSManagersFactory
|
||||
from uds.osmanagers.NoneOsManager.Manager import NoneOSManager
|
||||
|
||||
# This os manager exists for testing purposes only, do not register nor use it on a production environment
|
||||
#OSManagersFactory.factory().insert(NoneOSManager)
|
Binary file not shown.
Before Width: | Height: | Size: 1.2 KiB |
@ -12,7 +12,7 @@
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.managers.CryptoManager import CryptoManager
|
||||
from uds.core.osmanagers.BaseOsManager import BaseOSManager, State
|
||||
from uds.core import osmanagers
|
||||
from WindowsOsManager import WindowsOsManager, scrambleMsg
|
||||
|
||||
import logging
|
||||
@ -37,11 +37,11 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
super(WinDomainOsManager, self).__init__(environment, values)
|
||||
if values != None:
|
||||
if values['domain'] == '':
|
||||
raise BaseOSManager.ValidationException(_('Must provide a domain!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a domain!!!'))
|
||||
if values['account'] == '':
|
||||
raise BaseOSManager.ValidationException(_('Must provide an account to add machines to domain!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an account to add machines to domain!!!'))
|
||||
if values['password'] == '':
|
||||
raise BaseOSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
self._domain = values['domain']
|
||||
self._ou = values['ou']
|
||||
self._account = values['account']
|
||||
|
@ -11,8 +11,9 @@
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core.osmanagers.BaseOsManager import BaseOSManager, State
|
||||
from uds.core import osmanagers
|
||||
from uds.core.managers.UserServiceManager import UserServiceManager
|
||||
from uds.core.util.State import State
|
||||
|
||||
import logging
|
||||
|
||||
@ -31,7 +32,7 @@ def scrambleMsg(data):
|
||||
return "".join(res).encode('hex')
|
||||
|
||||
|
||||
class WindowsOsManager(BaseOSManager):
|
||||
class WindowsOsManager(osmanagers.OSManager):
|
||||
typeName = _('Windows Basic OS Manager')
|
||||
typeType = 'WindowsManager'
|
||||
typeDescription = _('Os Manager to control windows machines without domain. (Basically renames machine)')
|
||||
@ -48,9 +49,9 @@ class WindowsOsManager(BaseOSManager):
|
||||
try:
|
||||
len = int(len)
|
||||
except Exception:
|
||||
raise BaseOSManager.ValidationException(_('Length must be numeric!!'))
|
||||
raise osmanagers.OSManager.ValidationException(_('Length must be numeric!!'))
|
||||
if len > 6 or len < 1:
|
||||
raise BaseOSManager.ValidationException(_('Length must be betwen 1 and six'))
|
||||
raise osmanagers.OSManager.ValidationException(_('Length must be betwen 1 and six'))
|
||||
return len
|
||||
|
||||
def __init__(self,environment, values):
|
||||
|
@ -28,14 +28,36 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
OS Manager modules for uds are contained inside this package.
|
||||
To create a new OS manager module, you will need to follow this steps:
|
||||
1.- Create the os manager module, probably based on an existing one
|
||||
2.- Insert the module package as child of this package
|
||||
3.- Import the class of your os manager module at __init__. For example::
|
||||
from OSManager import SimpleOSManager
|
||||
4.- Done. At Server restart, the module will be recognized, loaded and treated
|
||||
|
||||
The registration of modules is done locating subclases of :py:class:`uds.core.auths.Authentication`
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import os.path, pkgutil
|
||||
import sys
|
||||
import uds.core
|
||||
|
||||
# Dynamically import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
__import__(name, globals(), locals(), [], -1)
|
||||
def __init__():
|
||||
'''
|
||||
This imports all packages that are descendant of this package, and, after that,
|
||||
it register all subclases of service provider as
|
||||
'''
|
||||
import os.path, pkgutil
|
||||
import sys
|
||||
from uds.core import osmanagers
|
||||
|
||||
# Dinamycally import children of this package. The __init__.py files must register, if needed, inside ServiceProviderFactory
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
__import__(name, globals(), locals(), [], -1)
|
||||
|
||||
p = osmanagers.OSManager
|
||||
# This is marked as error in IDE, but it's not (__subclasses__)
|
||||
for cls in p.__subclasses__():
|
||||
osmanagers.factory().insert(cls)
|
||||
|
||||
__init__()
|
||||
|
@ -28,12 +28,12 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
Authentication modules for uds are contained inside this package.
|
||||
To create a new authentication module, you will need to follow this steps:
|
||||
1.- Create the authentication module, probably based on an existing one
|
||||
Service modules for uds are contained inside this package.
|
||||
To create a new service module, you will need to follow this steps:
|
||||
1.- Create the service module, probably based on an existing one
|
||||
2.- Insert the module package as child of this package
|
||||
3.- Import the class of your authentication module at __init__. For example::
|
||||
from Authenticator import SimpleAthenticator
|
||||
3.- Import the class of your service module at __init__. For example::
|
||||
from Service import SimpleService
|
||||
4.- Done. At Server restart, the module will be recognized, loaded and treated
|
||||
|
||||
The registration of modules is done locating subclases of :py:class:`uds.core.auths.Authentication`
|
||||
|
@ -31,14 +31,12 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.transports.TransportsFactory import TransportsFactory
|
||||
from uds.core.managers.UserPrefsManager import UserPrefsManager, CommonPrefs
|
||||
from uds.core.managers.DownloadsManager import DownloadsManager
|
||||
from NXTransport import NXTransport
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
import os.path, sys
|
||||
|
||||
TransportsFactory.factory().insert(NXTransport)
|
||||
UserPrefsManager.manager().registerPrefs('nx', _('NX Protocol'),
|
||||
[
|
||||
CommonPrefs.screenSizePref
|
||||
|
@ -9,14 +9,11 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.transports.TransportsFactory import TransportsFactory
|
||||
from uds.core.managers.UserPrefsManager import UserPrefsManager, CommonPrefs
|
||||
from uds.transports.RDP.RDPTransport import RDPTransport
|
||||
from uds.transports.RDP.TSRDPTransport import TSRDPTransport
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
|
||||
TransportsFactory.factory().insert(RDPTransport)
|
||||
TransportsFactory.factory().insert(TSRDPTransport)
|
||||
UserPrefsManager.manager().registerPrefs('rdp', _('Remote Desktop Protocol'),
|
||||
[
|
||||
CommonPrefs.screenSizePref,
|
||||
|
@ -31,14 +31,12 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.transports.TransportsFactory import TransportsFactory
|
||||
from uds.core.managers.UserPrefsManager import UserPrefsManager, CommonPrefs
|
||||
from uds.core.managers.DownloadsManager import DownloadsManager
|
||||
from TSNXTransport import TSNXTransport
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
import os.path, sys
|
||||
|
||||
TransportsFactory.factory().insert(TSNXTransport)
|
||||
UserPrefsManager.manager().registerPrefs('nx', _('NX Protocol'),
|
||||
[
|
||||
CommonPrefs.screenSizePref
|
||||
|
@ -40,7 +40,7 @@ from ..util.Helpers import dictFromData
|
||||
from ..auths.AdminAuth import needs_credentials
|
||||
from uds.core.Environment import Environment
|
||||
import logging
|
||||
from uds.core.osmanagers.BaseOsManager import BaseOSManager
|
||||
from uds.core import osmanagers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -108,7 +108,7 @@ def createOSManager(credentials, type, data):
|
||||
sp = OSManager.objects.create(name = dict['name'], comments = dict['comments'], data_type = type)
|
||||
sp.data = sp.getInstance(dict).serialize()
|
||||
sp.save()
|
||||
except BaseOSManager.ValidationException, e:
|
||||
except osmanagers.OSManager.ValidationException, e:
|
||||
sp.delete()
|
||||
raise ValidationException(str(e))
|
||||
except IntegrityError: # Must be exception at creation
|
||||
|
Loading…
Reference in New Issue
Block a user