added "backup host" to xen server in case of connection failure to main server

This commit is contained in:
Adolfo Gómez García 2021-04-06 12:12:57 +02:00
parent 4357ef3be8
commit 9340e3c3c1
2 changed files with 112 additions and 20 deletions

View File

@ -34,9 +34,11 @@ import typing
from django.utils.translation import ugettext_noop as _
from uds.core.services import ServiceProvider
from uds.core.ui import gui
# from uds.core.util import validators
from .xen_client import XenServer
# from xen_client import XenFailure, XenFault
from .service import XenLinkedService
@ -50,6 +52,7 @@ if typing.TYPE_CHECKING:
CACHE_TIME_FOR_SERVER = 1800
class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
"""
This class represents the sample services provider
@ -67,6 +70,7 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
we MUST register it at package __init__.
"""
# : What kind of services we offer, this are classes inherited from Service
offers = [XenLinkedService]
# : Name to show the administrator. This string will be translated BEFORE
@ -91,18 +95,82 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
# but used for sample purposes
# If we don't indicate an order, the output order of fields will be
# "random"
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('XenServer Server IP or Hostname'), required=True)
username = gui.TextField(length=32, label=_('Username'), order=2, tooltip=_('User with valid privileges on XenServer'), required=True, defvalue='root')
password = gui.PasswordField(lenth=32, label=_('Password'), order=3, tooltip=_('Password of the user of XenServer'), required=True)
host = gui.TextField(
length=64,
label=_('Host'),
order=1,
tooltip=_('XenServer Server IP or Hostname'),
required=True,
)
username = gui.TextField(
length=32,
label=_('Username'),
order=2,
tooltip=_('User with valid privileges on XenServer'),
required=True,
defvalue='root',
)
password = gui.PasswordField(
lenth=32,
label=_('Password'),
order=3,
tooltip=_('Password of the user of XenServer'),
required=True,
)
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
maxPreparingServices = gui.NumericField(
length=3,
label=_('Creation concurrency'),
defvalue='10',
minValue=1,
maxValue=65536,
order=50,
tooltip=_('Maximum number of concurrently creating VMs'),
required=True,
tab=gui.ADVANCED_TAB,
)
maxRemovingServices = gui.NumericField(
length=3,
label=_('Removal concurrency'),
defvalue='5',
minValue=1,
maxValue=65536,
order=51,
tooltip=_('Maximum number of concurrently removing VMs'),
required=True,
tab=gui.ADVANCED_TAB,
)
macsRange = gui.TextField(length=36, label=_('Macs range'), defvalue='02:46:00:00:00:00-02:46:00:FF:FF:FF', order=90, rdonly=True,
tooltip=_('Range of valid macs for created machines'), required=True, tab=gui.ADVANCED_TAB)
verifySSL = gui.CheckBoxField(label=_('Verify Certificate'), order=91,
tooltip=_('If selected, certificate will be checked against system valid certificate providers'),
tab=gui.ADVANCED_TAB, defvalue=gui.FALSE)
macsRange = gui.TextField(
length=36,
label=_('Macs range'),
defvalue='02:46:00:00:00:00-02:46:00:FF:FF:FF',
order=90,
rdonly=True,
tooltip=_('Range of valid macs for created machines'),
required=True,
tab=gui.ADVANCED_TAB,
)
verifySSL = gui.CheckBoxField(
label=_('Verify Certificate'),
order=91,
tooltip=_(
'If selected, certificate will be checked against system valid certificate providers'
),
tab=gui.ADVANCED_TAB,
defvalue=gui.FALSE,
)
hostBackup = gui.TextField(
length=64,
label=_('Backup Host'),
order=92,
tooltip=_(
'XenServer BACKUP IP or Hostname (used on connection failure to main server)'
),
tab=gui.ADVANCED_TAB,
required=False,
)
_api: typing.Optional[XenServer]
@ -115,7 +183,15 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
Returns the connection API object for XenServer (using XenServersdk)
"""
if not self._api or force:
self._api = XenServer(self.host.value, 443, self.username.value, self.password.value, True, self.verifySSL.isTrue())
self._api = XenServer(
self.host.value,
self.hostBackup.value,
443,
self.username.value,
self.password.value,
True,
self.verifySSL.isTrue(),
)
return self._api
@ -158,7 +234,9 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
# Any other state, raises an exception
raise Exception(str(ts['result'])) # Should be error message
def getMachines(self, force: bool = False) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
def getMachines(
self, force: bool = False
) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
"""
Obtains the list of machines inside XenServer.
Machines starting with UDS are filtered out
@ -179,7 +257,9 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
continue
yield m
def getStorages(self, force: bool = False) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
def getStorages(
self, force: bool = False
) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
"""
Obtains the list of storages inside XenServer.
@ -196,7 +276,9 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
"""
return self.__getApi().getSRs()
def getStorageInfo(self, storageId: str, force=False) -> typing.MutableMapping[str, typing.Any]:
def getStorageInfo(
self, storageId: str, force=False
) -> typing.MutableMapping[str, typing.Any]:
"""
Obtains the storage info
@ -218,7 +300,9 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
"""
return self.__getApi().getSRInfo(storageId)
def getNetworks(self, force: bool = False) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
def getNetworks(
self, force: bool = False
) -> typing.Iterable[typing.MutableMapping[str, typing.Any]]:
return self.__getApi().getNetworks()
def cloneForTemplate(self, name: str, comments: str, machineId: str, sr: str):
@ -356,7 +440,9 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
self.__getApi().removeVM(machineId)
def configureVM(self, machineId: str, netId: str, mac: str, memory: int) -> None:
self.__getApi().configureVM(machineId, mac={'network': netId, 'mac': mac}, memory=memory)
self.__getApi().configureVM(
machineId, mac={'network': netId, 'mac': mac}, memory=memory
)
def provisionVM(self, machineId: str, asnc: bool = True) -> str:
return self.__getApi().provisionVM(machineId, asnc=asnc)

View File

@ -100,6 +100,7 @@ class XenPowerState: # pylint: disable=too-few-public-methods
class XenServer: # pylint: disable=too-many-public-methods
_originalHost: str
_host: str
_host_backup: str
_port: str
_useSSL: bool
_verifySSL: bool
@ -112,8 +113,9 @@ class XenServer: # pylint: disable=too-many-public-methods
_poolName: str
_apiVersion: str
def __init__(self, host: 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)
self._useSSL = bool(useSSL)
self._verifySSL = bool(verifySSL)
@ -189,9 +191,13 @@ class XenServer: # pylint: disable=too-many-public-methods
self.login()
else:
raise XenFailure(e.details)
except Exception as e:
logger.exception('Unrecognized xenapi exception')
raise
except Exception:
if self._host == self._host_backup or not self._host_backup:
logger.exception('Unrecognized xenapi exception')
raise
# Retry connection to backup host
self._host = self._host_backup
self.login()
def test(self) -> None:
self.login(False)