forked from ungleich-public/dynamicweb
Do not break the VM list when a VM's OpenNebula template was deleted
The "my virtual machines" page showed "We could not load your VMs due to a
backend connection error" for any user owning a VM whose template had been
removed from OpenNebula. OpenNebulaManager.get_template() converted every
failure, including WrongIdError for a missing template, into
ConnectionRefusedError, and VirtualMachineSerializer.get_configuration()
let that propagate, so one VM with a stale template id took down the whole
list. The only log output was an empty ERROR line, because WrongIdError
has no message.
* Add opennebula_api.exceptions.TemplateNotFoundError and raise it from
get_template() for a missing template; keep ConnectionRefusedError for
genuine backend failures and log them with a traceback.
* Add OpenNebulaManager.get_template_names() and resolve_template_id() so
the serializer fetches the template pool once per list instead of
constructing an OpenNebulaManager and fetching the pool for every VM.
* get_configuration() now falls back to the template name embedded in the
VM name ("<template>-<vm id>") when the template is missing or the pool
cannot be fetched, and logs why.
* Replace str.lstrip('public-') with a real prefix strip (lstrip removes a
character set, so "public-ubuntu" became "ntu") and also strip
"ipv6only-".
* ProcessVMSelectionMixin shows "configuration is no longer available"
instead of an unhandled error when ordering a retired template.
* VirtualMachinesPlanListView logs the exception behind the banner.
* Add mock-based unit tests for the fallback, the UPDATED_TEMPLATES
mapping, the single pool fetch and the new exception.
The UPDATED_TEMPLATES setting keeps working as an operational override for
mapping retired template ids to their replacements.
This commit is contained in:
parent
9cdf4593cf
commit
cb16114aba
6 changed files with 268 additions and 23 deletions
|
|
@ -9,7 +9,10 @@ from oca.pool import WrongNameError, WrongIdError
|
|||
from hosting.models import HostingOrder
|
||||
from utils.models import CustomUser
|
||||
from utils.tasks import save_ssh_key, save_ssh_key_error_handler
|
||||
from .exceptions import KeyExistsError, UserExistsError, UserCredentialError
|
||||
from .exceptions import (
|
||||
KeyExistsError, UserExistsError, UserCredentialError,
|
||||
TemplateNotFoundError
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -425,16 +428,60 @@ class OpenNebulaManager():
|
|||
except:
|
||||
return []
|
||||
|
||||
def get_template(self, template_id):
|
||||
@staticmethod
|
||||
def resolve_template_id(template_id):
|
||||
"""
|
||||
Map a (possibly retired) template id to its replacement, as
|
||||
configured in settings.UPDATED_TEMPLATES_DICT. Ids without a
|
||||
mapping are returned unchanged.
|
||||
"""
|
||||
template_id = int(template_id)
|
||||
return settings.UPDATED_TEMPLATES_DICT.get(template_id, template_id)
|
||||
|
||||
def get_template_names(self):
|
||||
"""
|
||||
Return a dict {template_id: template_name} of every template
|
||||
visible to oneadmin, in a single RPC call.
|
||||
|
||||
:raises ConnectionRefusedError: if OpenNebula is unreachable
|
||||
"""
|
||||
try:
|
||||
template_pool = self._get_template_pool()
|
||||
return dict(
|
||||
(template.id, template.name) for template in template_pool
|
||||
)
|
||||
except ConnectionRefusedError:
|
||||
raise
|
||||
except Exception:
|
||||
# Any other failure (socket timeout, XML-RPC fault, ...) is a
|
||||
# backend problem as far as the callers are concerned
|
||||
logger.exception("Could not fetch the OpenNebula template pool")
|
||||
raise ConnectionRefusedError
|
||||
|
||||
def get_template(self, template_id):
|
||||
"""
|
||||
Return the oca template object for the given id.
|
||||
|
||||
:raises TemplateNotFoundError: if the template (after applying
|
||||
settings.UPDATED_TEMPLATES_DICT) does not exist in OpenNebula
|
||||
:raises ConnectionRefusedError: if OpenNebula is unreachable or
|
||||
fails in any other way
|
||||
"""
|
||||
template_id = self.resolve_template_id(template_id)
|
||||
try:
|
||||
template_pool = self._get_template_pool()
|
||||
if template_id in settings.UPDATED_TEMPLATES_DICT.keys():
|
||||
template_id = settings.UPDATED_TEMPLATES_DICT[template_id]
|
||||
return template_pool.get_by_id(template_id)
|
||||
except Exception as ex:
|
||||
logger.debug("Template Id we are looking for : %s" % template_id)
|
||||
logger.error(str(ex))
|
||||
except WrongIdError:
|
||||
logger.error(
|
||||
"OpenNebula template %s does not exist" % template_id
|
||||
)
|
||||
raise TemplateNotFoundError(template_id)
|
||||
except ConnectionRefusedError:
|
||||
raise
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Could not fetch OpenNebula template %s" % template_id
|
||||
)
|
||||
raise ConnectionRefusedError
|
||||
|
||||
def create_template(self, name, cores, memory, disk_size, core_price,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue