More formating

This commit is contained in:
Adolfo Gómez García 2021-08-23 14:59:07 +02:00
parent 1b7076e645
commit c72bcf4200
11 changed files with 291 additions and 113 deletions

View File

@ -118,7 +118,9 @@ class SampleUserDeploymentOne(services.UserDeployment):
"""
name: str = typing.cast(str, self.storage.readData('name'))
if name is None:
name = self.nameGenerator().get(self.service().getBaseName() + '-' + self.service().getColour(), 3)
name = self.nameGenerator().get(
self.service().getBaseName() + '-' + self.service().getColour(), 3
)
# Store value for persistence
self.storage.saveData('name', name)
@ -269,7 +271,10 @@ class SampleUserDeploymentOne(services.UserDeployment):
destroying, and cancel will simply invoke destroy
"""
import random
countStr: typing.Optional[str] = typing.cast(str, self.storage.readData('count'))
countStr: typing.Optional[str] = typing.cast(
str, self.storage.readData('count')
)
count: int = 0
if countStr:
count = int(countStr) + 1

View File

@ -119,8 +119,9 @@ class SampleUserDeploymentTwo(services.UserDeployment):
beside the values, so we can, at a later stage, treat with old
data for current modules.
"""
data = '\t'.join(['v1', self._name, self._ip, self._mac, self._error,
str(self._count)])
data = '\t'.join(
['v1', self._name, self._ip, self._mac, self._error, str(self._count)]
)
return codecs.encode(data.encode(), encoding='zip') # type: ignore
def unmarshal(self, data: bytes) -> None:

View File

@ -66,6 +66,7 @@ class Provider(services.ServiceProvider):
we MUST register it at package __init__.
"""
# : What kind of services we offer, this are classes inherited from Service
offers = [ServiceOne, ServiceTwo]
# : Name to show the administrator. This string will be translated BEFORE
@ -107,7 +108,7 @@ class Provider(services.ServiceProvider):
label=_('Your pet\'s name'),
tooltip=_('If you like, write the name of your pet'),
requred=False,
defvalue='Tux' # : This will not get translated
defvalue='Tux', # : This will not get translated
)
# : Age of Methuselah (matusalén in spanish)
# : in Spain there is a well-known to say that something is very old,
@ -118,7 +119,7 @@ class Provider(services.ServiceProvider):
label=_('Age of Methuselah'),
tooltip=_('If you know it, please, tell me!!!'),
required=True, # : Numeric fields have always a value, so this not really needed
defvalue='4500'
defvalue='4500',
)
# : Is Methuselah istill alive?
@ -126,7 +127,7 @@ class Provider(services.ServiceProvider):
order=4,
label=_('Is Methuselah still alive?'),
tooltip=_('If you fail, this will not get saved :-)'),
defvalue=gui.TRUE # : By default, at new item, check this
defvalue=gui.TRUE, # : By default, at new item, check this
)
methText = gui.TextField(
@ -136,7 +137,7 @@ class Provider(services.ServiceProvider):
label=_('Text area'),
tooltip=_('This is a text area'),
requred=False,
defvalue='Write\nsomething' # : This will not get translated
defvalue='Write\nsomething', # : This will not get translated
)
# There is more fields type, but not here the best place to cover it
@ -154,7 +155,9 @@ class Provider(services.ServiceProvider):
# values are only passed from administration client. Internals
# instantiations are always empty.
if values and self.methAlive.isTrue():
raise services.ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)'))
raise services.ServiceProvider.ValidationException(
_('Methuselah is not alive!!! :-)')
)
# Marshal and unmarshal are defaults ones, also enought
@ -162,7 +165,9 @@ class Provider(services.ServiceProvider):
# base class so we don't have to mess with all those things...
@staticmethod
def test(env: 'Environment', data: typing.Dict[str, str]) -> typing.List[typing.Any]:
def test(
env: 'Environment', data: typing.Dict[str, str]
) -> typing.List[typing.Any]:
"""
Create your test method here so the admin can push the "check" button
and this gets executed.
@ -186,7 +191,11 @@ class Provider(services.ServiceProvider):
try:
# We instantiate the provider, but this may fail...
instance = Provider(env, data)
logger.debug('Methuselah has %s years and is %s :-)', instance.methAge.value, instance.methAlive.value)
logger.debug(
'Methuselah has %s years and is %s :-)',
instance.methAge.value,
instance.methAlive.value,
)
except services.ServiceProvider.ValidationException as e:
# If we say that meth is alive, instantiation will
return [False, str(e)]

View File

@ -84,7 +84,9 @@ class SamplePublication(services.Publication):
it's expressed in seconds, (i.e. "suggestedTime = 10")
"""
suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds
suggestedTime = (
5 # : Suggested recheck time if publication is unfinished in seconds
)
_name: str = ''
_reason: str = ''
_number: int = -1
@ -217,7 +219,9 @@ class SamplePublication(services.Publication):
Returned value, if any, is ignored
"""
# Make simply a random string
self._name = ''.join(random.SystemRandom().choices(string.ascii_uppercase + string.digits, k=10))
self._name = ''.join(
random.SystemRandom().choices(string.ascii_uppercase + string.digits, k=10)
)
def reasonOfError(self) -> str:
"""

View File

@ -49,6 +49,7 @@ if typing.TYPE_CHECKING:
logger = logging.getLogger(__name__)
class ServiceOne(services.Service):
"""
Basic service, the first part (variables) include the description of the service.
@ -71,6 +72,7 @@ class ServiceOne(services.Service):
information.
"""
# : Name to show the administrator. This string will be translated BEFORE
# : sending it to administration interface, so don't forget to
# : mark it as _ (using ugettext_noop)
@ -130,9 +132,9 @@ class ServiceOne(services.Service):
gui.choiceItem('red', 'Red'),
gui.choiceItem('green', 'Green'),
gui.choiceItem('blue', 'Blue'),
gui.choiceItem('nonsense', 'Blagenta')
gui.choiceItem('nonsense', 'Blagenta'),
],
defvalue='1' # Default value is the ID of the choicefield
defvalue='1', # Default value is the ID of the choicefield
)
passw = gui.PasswordField(
@ -140,7 +142,7 @@ class ServiceOne(services.Service):
label=_('Password'),
tooltip=_('Password for testing purposes'),
required=True,
defvalue='1234' # : Default password are nonsense?? :-)
defvalue='1234', # : Default password are nonsense?? :-)
)
baseName = gui.TextField(
@ -149,7 +151,7 @@ class ServiceOne(services.Service):
tooltip=_('Base name for this user services'),
# In this case, the choice can have none value selected by default
required=True,
defvalue='' # Default value is the ID of the choicefield
defvalue='', # Default value is the ID of the choicefield
)
def initialize(self, values: 'Module.ValuesType') -> None:
@ -165,13 +167,13 @@ class ServiceOne(services.Service):
# so we only need to validate params if values is not None
if values:
if self.colour.value == 'nonsense':
raise services.Service.ValidationException('The selected colour is invalid!!!')
raise services.Service.ValidationException(
'The selected colour is invalid!!!'
)
# Services itself are non testeable right now, so we don't even have
# to provide one!!!
# Congratulations!!!, the needed part of your first simple service is done!
# Now you can go to administration panel, and check it
#
@ -200,6 +202,7 @@ class ServiceTwo(services.Service):
"""
Just a second service, no comments here (almost same that ServiceOne
"""
typeName = _('Sample Service Two')
typeType = 'SampleService2'
typeDescription = _('Sample (and dummy) service ONE+ONE')
@ -222,7 +225,6 @@ class ServiceTwo(services.Service):
# : Types of deploys (services in cache and/or assigned to users)
deployedType = SampleUserDeploymentTwo
# Gui, we will use here the EditableList field
names = gui.EditableList(label=_('List of names'))

View File

@ -48,7 +48,20 @@ if typing.TYPE_CHECKING:
logger = logging.getLogger(__name__)
opCreate, opStart, opStop, opSuspend, opRemove, opWait, opError, opFinish, opRetry, opConfigure, opProvision, opWaitSuspend = range(12)
(
opCreate,
opStart,
opStop,
opSuspend,
opRemove,
opWait,
opError,
opFinish,
opRetry,
opConfigure,
opProvision,
opWaitSuspend,
) = range(12)
NO_MORE_NAMES = 'NO-NAME-ERROR'
@ -80,16 +93,18 @@ class XenLinkedDeployment(UserDeployment):
# Serializable needed methods
def marshal(self) -> bytes:
return b'\1'.join([
b'v1',
self._name.encode('utf8'),
self._ip.encode('utf8'),
self._mac.encode('utf8'),
self._vmid.encode('utf8'),
self._reason.encode('utf8'),
pickle.dumps(self._queue, protocol=0),
self._task.encode('utf8')
])
return b'\1'.join(
[
b'v1',
self._name.encode('utf8'),
self._ip.encode('utf8'),
self._mac.encode('utf8'),
self._vmid.encode('utf8'),
self._reason.encode('utf8'),
pickle.dumps(self._queue, protocol=0),
self._task.encode('utf8'),
]
)
def unmarshal(self, data: bytes) -> None:
vals = data.split(b'\1')
@ -106,7 +121,9 @@ class XenLinkedDeployment(UserDeployment):
def getName(self) -> str:
if not self._name:
try:
self._name = self.nameGenerator().get(self.service().getBaseName(), self.service().getLenName())
self._name = self.nameGenerator().get(
self.service().getBaseName(), self.service().getLenName()
)
except KeyError:
return NO_MORE_NAMES
return self._name
@ -168,7 +185,16 @@ class XenLinkedDeployment(UserDeployment):
if forLevel2 is False:
self._queue = [opCreate, opConfigure, opProvision, opStart, opFinish]
else:
self._queue = [opCreate, opConfigure, opProvision, opStart, opWait, opWaitSuspend, opSuspend, opFinish]
self._queue = [
opCreate,
opConfigure,
opProvision,
opStart,
opWait,
opWaitSuspend,
opSuspend,
opFinish,
]
def __getCurrentOp(self) -> int:
if len(self._queue) == 0:
@ -196,7 +222,11 @@ class XenLinkedDeployment(UserDeployment):
if self._vmid != '': # Powers off and delete VM
try:
state = self.service().getVMPowerState(self._vmid)
if state in (XenPowerState.running, XenPowerState.paused, XenPowerState.suspended):
if state in (
XenPowerState.running,
XenPowerState.paused,
XenPowerState.suspended,
):
self.service().stopVM(self._vmid, False) # In sync mode
self.service().removeVM(self._vmid)
except Exception:
@ -226,14 +256,16 @@ class XenLinkedDeployment(UserDeployment):
opWait: self.__wait,
opRemove: self.__remove,
opConfigure: self.__configure,
opProvision: self.__provision
opProvision: self.__provision,
}
try:
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
if execFnc is None:
return self.__error('Unknown operation found at execution queue ({0})'.format(op))
return self.__error(
'Unknown operation found at execution queue ({0})'.format(op)
)
execFnc()
@ -265,9 +297,13 @@ class XenLinkedDeployment(UserDeployment):
templateId = self.publication().getTemplateId()
name = self.getName()
if name == NO_MORE_NAMES:
raise Exception('No more names available for this service. (Increase digits for this service to fix)')
raise Exception(
'No more names available for this service. (Increase digits for this service to fix)'
)
name = 'UDS service ' + self.service().sanitizeVmName(name) # oVirt don't let us to create machines with more than 15 chars!!!
name = 'UDS service ' + self.service().sanitizeVmName(
name
) # oVirt don't let us to create machines with more than 15 chars!!!
comments = 'UDS Linked clone'
self._task = self.service().startDeployFromTemplate(name, comments, templateId)
@ -282,7 +318,7 @@ class XenLinkedDeployment(UserDeployment):
"""
state = self.service().getVMPowerState(self._vmid)
if state not in(XenPowerState.halted, XenPowerState.suspended):
if state not in (XenPowerState.halted, XenPowerState.suspended):
self.__pushFrontOp(opStop)
self.__executeQueue()
else:
@ -348,7 +384,9 @@ class XenLinkedDeployment(UserDeployment):
"""
Makes machine usable on Xen
"""
self.service().provisionVM(self._vmid, False) # Let's try this in "sync" mode, this must be fast enough
self.service().provisionVM(
self._vmid, False
) # Let's try this in "sync" mode, this must be fast enough
return State.RUNNING
@ -434,14 +472,16 @@ class XenLinkedDeployment(UserDeployment):
opSuspend: self.__checkSuspend,
opRemove: self.__checkRemoved,
opConfigure: self.__checkConfigure,
opProvision: self.__checkProvision
opProvision: self.__checkProvision,
}
try:
chkFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
if chkFnc is None:
return self.__error('Unknown operation found at check queue ({})'.format(op))
return self.__error(
'Unknown operation found at check queue ({})'.format(op)
)
state = chkFnc()
if state == State.FINISHED:
@ -503,8 +543,16 @@ class XenLinkedDeployment(UserDeployment):
opFinish: 'finish',
opRetry: 'retry',
opConfigure: 'configuring',
opProvision: 'provisioning'
opProvision: 'provisioning',
}.get(op, '????')
def __debug(self, txt: str) -> None:
logger.debug('State at %s: name: %s, ip: %s, mac: %s, vmid:%s, queue: %s', txt, self._name, self._ip, self._mac, self._vmid, [XenLinkedDeployment.__op2str(op) for op in self._queue])
logger.debug(
'State at %s: name: %s, ip: %s, mac: %s, vmid:%s, queue: %s',
txt,
self._name,
self._ip,
self._mac,
self._vmid,
[XenLinkedDeployment.__op2str(op) for op in self._queue],
)

View File

@ -45,7 +45,9 @@ logger = logging.getLogger(__name__)
class XenPublication(Publication):
suggestedTime = 20 # : Suggested recheck time if publication is unfinished in seconds
suggestedTime = (
20 # : Suggested recheck time if publication is unfinished in seconds
)
_name: str = ''
_reason: str = ''
@ -61,23 +63,44 @@ class XenPublication(Publication):
"""
returns data from an instance of Sample Publication serialized
"""
return '\t'.join(['v1', self._name, self._reason, self._destroyAfter, self._templateId, self._state, self._task]).encode('utf8')
return '\t'.join(
[
'v1',
self._name,
self._reason,
self._destroyAfter,
self._templateId,
self._state,
self._task,
]
).encode('utf8')
def unmarshal(self, data: bytes) -> None:
"""
deserializes the data and loads it inside instance.
"""
#logger.debug('Data: {0}'.format(data))
# logger.debug('Data: {0}'.format(data))
vals = data.decode('utf8').split('\t')
if vals[0] == 'v1':
self._name, self._reason, self._destroyAfter, self._templateId, self._state, self._task = vals[1:]
(
self._name,
self._reason,
self._destroyAfter,
self._templateId,
self._state,
self._task,
) = vals[1:]
def publish(self) -> str:
"""
Realizes the publication of the service
"""
self._name = self.service().sanitizeVmName('UDS Pub ' + self.dsName() + "-" + str(self.revision()))
comments = _('UDS pub for {0} at {1}').format(self.dsName(), str(datetime.now()).split('.')[0])
self._name = self.service().sanitizeVmName(
'UDS Pub ' + self.dsName() + "-" + str(self.revision())
)
comments = _('UDS pub for {0} at {1}').format(
self.dsName(), str(datetime.now()).split('.')[0]
)
self._reason = '' # No error, no reason for it
self._destroyAfter = 'f'
self._state = 'ok'

View File

@ -54,6 +54,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
"""
# : Name to show the administrator. This string will be translated BEFORE
# : sending it to administration interface, so don't forget to
# : mark it as _ (using ugettext_noop)
@ -78,15 +79,13 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
usesCache = True
# : Tooltip shown to user when this item is pointed at admin interface, none
# : because we don't use it
cacheTooltip = _(
'Number of desired machines to keep running waiting for a user')
cacheTooltip = _('Number of desired machines to keep running waiting for a user')
# : If we need to generate a "Level 2" cache for this service (i.e., L1
# : could be running machines and L2 suspended machines)
usesCache_L2 = True
# : Tooltip shown to user when this item is pointed at admin interface, None
# : also because we don't use it
cacheTooltip_L2 = _(
'Number of desired machines to keep suspended waiting for use')
cacheTooltip_L2 = _('Number of desired machines to keep suspended waiting for use')
# : If the service needs a s.o. manager (managers are related to agents
# : provided by services itselfs, i.e. virtual machines with actors)
@ -109,8 +108,10 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
label=_("Storage SR"),
rdonly=False,
order=100,
tooltip=_('Storage where to publish and put incrementals (only shared storages are supported)'),
required=True
tooltip=_(
'Storage where to publish and put incrementals (only shared storages are supported)'
),
required=True,
)
minSpaceGB = gui.NumericField(
@ -119,7 +120,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
defvalue='32',
order=101,
tooltip=_('Minimal free space in GB'),
required=True
required=True,
)
machine = gui.ChoiceField(
@ -127,7 +128,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
order=110,
tooltip=_('Service base machine'),
tab=_('Machine'),
required=True
required=True,
)
network = gui.ChoiceField(
@ -136,17 +137,18 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
order=111,
tooltip=_('Network used for virtual machines'),
tab=_('Machine'),
required=True
required=True,
)
memory = gui.NumericField(
label=_("Memory (Mb)"),
length=4, defvalue=512,
length=4,
defvalue=512,
rdonly=False,
order=112,
tooltip=_('Memory assigned to machines'),
tab=_('Machine'),
required=True
required=True,
)
shadow = gui.NumericField(
@ -157,7 +159,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
order=113,
tooltip=_('Shadow memory multiplier (use with care)'),
tab=_('Machine'),
required=True
required=True,
)
baseName = gui.TextField(
@ -166,7 +168,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
order=114,
tooltip=_('Base name for clones from this machine'),
tab=_('Machine'),
required=True
required=True,
)
lenName = gui.NumericField(
@ -176,7 +178,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
order=115,
tooltip=_('Size of numeric part for the names of these machines'),
tab=_('Machine'),
required=True
required=True,
)
def initialize(self, values):
@ -191,7 +193,8 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
if int(self.memory.value) < 256:
raise Service.ValidationException(
_('The minimum allowed memory is 256 Mb'))
_('The minimum allowed memory is 256 Mb')
)
def parent(self) -> 'XenProvider':
return typing.cast('XenProvider', super().parent())
@ -201,14 +204,27 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
# This is that value is always '', so if we want to change something, we have to do it
# at defValue
machines_list = [gui.choiceItem(m['id'], m['name']) for m in self.parent().getMachines()]
machines_list = [
gui.choiceItem(m['id'], m['name']) for m in self.parent().getMachines()
]
storages_list = []
for storage in self.parent().getStorages():
space, free = storage['size'] / 1024, (storage['size'] - storage['used']) / 1024
storages_list.append(gui.choiceItem(storage['id'], "%s (%4.2f Gb/%4.2f Gb)" % (storage['name'], space, free)))
space, free = (
storage['size'] / 1024,
(storage['size'] - storage['used']) / 1024,
)
storages_list.append(
gui.choiceItem(
storage['id'],
"%s (%4.2f Gb/%4.2f Gb)" % (storage['name'], space, free),
)
)
network_list = [gui.choiceItem(net['id'], net['name']) for net in self.parent().getNetworks()]
network_list = [
gui.choiceItem(net['id'], net['name'])
for net in self.parent().getNetworks()
]
self.machine.setValues(machines_list)
self.datastore.setValues(storages_list)
@ -223,7 +239,11 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
logger.debug('Checking datastore space for %s: %s', self.datastore.value, info)
availableGB = (info['size'] - info['used']) / 1024
if availableGB < self.minSpaceGB.num():
raise Exception('Not enough free space available: (Needs at least {} GB and there is only {} GB '.format(self.minSpaceGB.num(), availableGB))
raise Exception(
'Not enough free space available: (Needs at least {} GB and there is only {} GB '.format(
self.minSpaceGB.num(), availableGB
)
)
def sanitizeVmName(self, name: str) -> str:
"""
@ -245,12 +265,18 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
Raises an exception if operation fails.
"""
logger.debug('Starting deploy of template from machine %s on datastore %s', self.machine.value, self.datastore.value)
logger.debug(
'Starting deploy of template from machine %s on datastore %s',
self.machine.value,
self.datastore.value,
)
# Checks datastore available space, raises exeception in no min available
self.datastoreHasSpace()
return self.parent().cloneForTemplate(name, comments, self.machine.value, self.datastore.value)
return self.parent().cloneForTemplate(
name, comments, self.machine.value, self.datastore.value
)
def convertToTemplate(self, machineId: str) -> None:
"""

View File

@ -69,8 +69,10 @@ translation = gettext.translation('xen-xm', fallback=True)
API_VERSION_1_1 = '1.1'
API_VERSION_1_2 = '1.2'
class Failure(Exception):
details: typing.List[typing.Any]
def __init__(self, details: typing.List[typing.Any]):
super().__init__()
self.details = details
@ -87,19 +89,24 @@ class Failure(Exception):
# dict([(str(i), self.details[i]) for i in range(len(self.details))])
return {str(i): d for i, d in enumerate(self.details)}
# Just a "constant" that we use to decide whether to retry the RPC
_RECONNECT_AND_RETRY = object()
class UDSHTTPConnection(httplib.HTTPConnection):
"""HTTPConnection subclass to allow HTTP over Unix domain sockets. """
"""HTTPConnection subclass to allow HTTP over Unix domain sockets."""
def connect(self):
path = self.host.replace("_", "/")
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(path)
class UDSHTTP(httplib.HTTPConnection):
_connection_class = UDSHTTPConnection
class UDSTransport(xmlrpclib.Transport):
_use_datetime: bool
_extra_headers: typing.List[typing.Tuple[str, str]]
@ -117,11 +124,14 @@ class UDSTransport(xmlrpclib.Transport):
def make_connection(self, host: str) -> httplib.HTTPConnection: # type: ignore # In our case, host is always an string
return UDSHTTPConnection(host)
def send_request(self, connection, handler, request_body, debug): # pylint: disable=arguments-differ
def send_request(
self, connection, handler, request_body, debug
): # pylint: disable=arguments-differ
connection.putrequest("POST", handler)
for key, value in self._extra_headers:
connection.putheader(key, value)
class Session(xmlrpclib.ServerProxy):
"""A server proxy and session manager for communicating with xapi using
the Xen-API.
@ -134,25 +144,40 @@ class Session(xmlrpclib.ServerProxy):
session.xenapi.session.logout()
"""
def __init__(self, uri, transport=None, encoding=None, verbose=0,
allow_none=1, ignore_ssl=False):
def __init__(
self,
uri,
transport=None,
encoding=None,
verbose=0,
allow_none=1,
ignore_ssl=False,
):
# Fix for CA-172901 (+ Python 2.4 compatibility)
# Fix for context=ctx ( < Python 2.7.9 compatibility)
if not (sys.version_info[0] <= 2 and sys.version_info[1] <= 7 and sys.version_info[2] <= 9) and ignore_ssl:
if (
not (
sys.version_info[0] <= 2
and sys.version_info[1] <= 7
and sys.version_info[2] <= 9
)
and ignore_ssl
):
ctx = ssl._create_unverified_context()
xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding,
verbose, allow_none, context=ctx)
xmlrpclib.ServerProxy.__init__(
self, uri, transport, encoding, verbose, allow_none, context=ctx
)
else:
xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding,
verbose, allow_none)
xmlrpclib.ServerProxy.__init__(
self, uri, transport, encoding, verbose, allow_none
)
self.transport = transport
self._session = None
self.last_login_method = None
self.last_login_params = None
self.API_version = API_VERSION_1_1
def xenapi_request(self, methodname, params):
if methodname.startswith('login'):
self._login(methodname, params)
@ -168,22 +193,20 @@ class Session(xmlrpclib.ServerProxy):
if result is _RECONNECT_AND_RETRY:
retry_count += 1
if self.last_login_method:
self._login(self.last_login_method,
self.last_login_params)
self._login(self.last_login_method, self.last_login_params)
else:
raise xmlrpclib.Fault(401, 'You must log in')
else:
return result
raise xmlrpclib.Fault(
500, 'Tried 3 times to get a valid session, but failed')
500, 'Tried 3 times to get a valid session, but failed'
)
def _login(self, method, params):
try:
result = _parse_result(
getattr(self, 'session.%s' % method)(*params))
result = _parse_result(getattr(self, 'session.%s' % method)(*params))
if result is _RECONNECT_AND_RETRY:
raise xmlrpclib.Fault(
500, 'Received SESSION_INVALID when logging in')
raise xmlrpclib.Fault(500, 'Received SESSION_INVALID when logging in')
self._session = result
self.last_login_method = method
self.last_login_params = params
@ -195,7 +218,7 @@ class Session(xmlrpclib.ServerProxy):
def _logout(self):
try:
if self.last_login_method.startswith("slave_local"):
if self.last_login_method.startswith("slave_local"): # type: ignore
return _parse_result(self.session.local_logout(self._session)) # type: ignore
else:
return _parse_result(self.session.logout(self._session)) # type: ignore
@ -210,7 +233,7 @@ class Session(xmlrpclib.ServerProxy):
host = self.xenapi.pool.get_master(pool)
major = self.xenapi.host.get_API_version_major(host)
minor = self.xenapi.host.get_API_version_minor(host)
return "%s.%s"%(major, minor)
return "%s.%s" % (major, minor)
def __getattr__(self, name):
if name == 'handle':
@ -224,12 +247,16 @@ class Session(xmlrpclib.ServerProxy):
else:
return xmlrpclib.ServerProxy.__getattr__(self, name)
def xapi_local():
return Session("http://_var_lib_xcp_xapi/", transport=UDSTransport())
def _parse_result(result):
if not isinstance(result, dict) or 'Status' not in result:
raise xmlrpclib.Fault(500, 'Missing Status in response from server: {}'.format(result))
raise xmlrpclib.Fault(
500, 'Missing Status in response from server: {}'.format(result)
)
if result['Status'] == 'Success':
if 'Value' in result:
return result['Value']
@ -258,7 +285,9 @@ class _Dispatcher:
if self.__name is None:
return _Dispatcher(self.__API_version, self.__send, name)
else:
return _Dispatcher(self.__API_version, self.__send, "%s.%s" % (self.__name, name))
return _Dispatcher(
self.__API_version, self.__send, "%s.%s" % (self.__name, name)
)
def __call__(self, *args):
return self.__send(self.__name, args)

View File

@ -38,6 +38,7 @@ logger = logging.getLogger(__name__)
TAG_TEMPLATE = "uds-template"
TAG_MACHINE = "uds-machine"
class XenFault(Exception):
pass
@ -113,7 +114,16 @@ class XenServer: # pylint: disable=too-many-public-methods
_poolName: str
_apiVersion: str
def __init__(self, host: str, host_backup: str, port: int, username: str, password: str, useSSL: bool = False, verifySSL: bool = False):
def __init__(
self,
host: str,
host_backup: str,
port: int,
username: str,
password: str,
useSSL: bool = False,
verifySSL: bool = False,
):
self._originalHost = self._host = host
self._host_backup = host_backup or ''
self._port = str(port)
@ -186,7 +196,11 @@ class XenServer: # pylint: disable=too-many-public-methods
self._poolName = str(self.getPoolName())
except XenAPI.Failure as e: # XenAPI.Failure: ['HOST_IS_SLAVE', '172.27.0.29'] indicates that this host is an slave of 172.27.0.29, connect to it...
if switchToMaster and e.details[0] == 'HOST_IS_SLAVE':
logger.info('%s is an Slave, connecting to master at %s', self._host, e.details[1])
logger.info(
'%s is an Slave, connecting to master at %s',
self._host,
e.details[1],
)
self._host = e.details[1]
self.login()
else:
@ -246,7 +260,11 @@ class XenServer: # pylint: disable=too-many-public-methods
status = 'failure'
# Removes <value></value> if present
if result and not isinstance(result, XenFailure) and result.startswith('<value>'):
if (
result
and not isinstance(result, XenFailure)
and result.startswith('<value>')
):
result = result[7:-8]
if destroyTask:
@ -255,14 +273,18 @@ class XenServer: # pylint: disable=too-many-public-methods
except Exception as e:
logger.warning('Destroy task %s returned error %s', task, str(e))
return {'result': result, 'progress': progress, 'status':str(status)}
return {'result': result, 'progress': progress, 'status': str(status)}
def getSRs(self) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
for srId in self.SR.get_all():
# Only valid SR shared, non iso
name_label = self.SR.get_name_label(srId)
# Skip non valid...
if self.SR.get_content_type(srId) == 'iso' or self.SR.get_shared(srId) is False or name_label == '':
if (
self.SR.get_content_type(srId) == 'iso'
or self.SR.get_shared(srId) is False
or name_label == ''
):
continue
valid = True
@ -276,7 +298,7 @@ class XenServer: # pylint: disable=too-many-public-methods
'id': srId,
'name': name_label,
'size': XenServer.toMb(self.SR.get_physical_size(srId)),
'used': XenServer.toMb(self.SR.get_physical_utilisation(srId))
'used': XenServer.toMb(self.SR.get_physical_utilisation(srId)),
}
def getSRInfo(self, srId: str) -> typing.MutableMapping[str, typing.Any]:
@ -284,22 +306,24 @@ class XenServer: # pylint: disable=too-many-public-methods
'id': srId,
'name': self.SR.get_name_label(srId),
'size': XenServer.toMb(self.SR.get_physical_size(srId)),
'used': XenServer.toMb(self.SR.get_physical_utilisation(srId))
'used': XenServer.toMb(self.SR.get_physical_utilisation(srId)),
}
def getNetworks(self) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
for netId in self.network.get_all():
if self.network.get_other_config(netId).get('is_host_internal_management_network', False) is False:
if (
self.network.get_other_config(netId).get(
'is_host_internal_management_network', False
)
is False
):
yield {
'id': netId,
'name': self.network.get_name_label(netId),
}
def getNetworkInfo(self, netId: str) -> typing.MutableMapping[str, typing.Any]:
return {
'id': netId,
'name': self.network.get_name_label(netId)
}
return {'id': netId, 'name': self.network.get_name_label(netId)}
def getVMs(self) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
try:
@ -308,8 +332,7 @@ class XenServer: # pylint: disable=too-many-public-methods
# if self.VM.get_is_a_template(vm): # Sample set_tags, easy..
# self.VM.set_tags(vm, ['template'])
# continue
if self.VM.get_is_control_domain(vm) or \
self.VM.get_is_a_template(vm):
if self.VM.get_is_control_domain(vm) or self.VM.get_is_a_template(vm):
continue
yield {'id': vm, 'name': self.VM.get_name_label(vm)}
@ -382,7 +405,9 @@ class XenServer: # pylint: disable=too-many-public-methods
return self.Async.VM.resume(vmId, False, False)
return self.VM.resume(vmId, False, False)
def cloneVM(self, vmId: str, targetName: str, targetSR: typing.Optional[str] = None) -> str:
def cloneVM(
self, vmId: str, targetName: str, targetSR: typing.Optional[str] = None
) -> str:
"""
If targetSR is NONE:
Clones the specified VM, making a new VM.
@ -402,11 +427,15 @@ class XenServer: # pylint: disable=too-many-public-methods
try:
if targetSR:
if 'copy' not in operations:
raise XenException('Copy is not supported for this machine (maybe it\'s powered on?)')
raise XenException(
'Copy is not supported for this machine (maybe it\'s powered on?)'
)
task = self.Async.VM.copy(vmId, targetName, targetSR)
else:
if 'clone' not in operations:
raise XenException('Clone is not supported for this machine (maybe it\'s powered on?)')
raise XenException(
'Clone is not supported for this machine (maybe it\'s powered on?)'
)
task = self.Async.VM.clone(vmId, targetName)
return task
except XenAPI.Failure as e:
@ -490,7 +519,9 @@ class XenServer: # pylint: disable=too-many-public-methods
operations = self.VM.get_allowed_operations(vmId)
logger.debug('Allowed operations: %s', operations)
if 'make_into_template' not in operations:
raise XenException('Convert in template is not supported for this machine')
raise XenException(
'Convert in template is not supported for this machine'
)
self.VM.set_is_a_template(vmId, True)
# Apply that is an "UDS Template" taggint it

View File

@ -63,7 +63,7 @@ def __init__():
for _, name, _ in pkgutil.iter_modules([pkgpath]):
# __import__('uds.services.' + name, globals(), locals(), [])
importlib.import_module('.' + name, __name__) # import module
importlib.invalidate_caches()
for p in [services.ServiceProvider]: