dynamicweb/hosting/mixins.py
PCoder cb16114aba 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.
2026-10-19 20:53:32 +05:30

45 lines
1.7 KiB
Python

from django.contrib import messages
from django.shortcuts import redirect
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from opennebula_api.exceptions import TemplateNotFoundError
from opennebula_api.serializers import VirtualMachineTemplateSerializer
from opennebula_api.models import OpenNebulaManager
from .models import HostingPlan
class ProcessVMSelectionMixin(object):
def post(self, request, *args, **kwargs):
template_id = int(request.POST.get('vm_template_id'))
configuration_id = int(request.POST.get('configuration'))
try:
template = OpenNebulaManager().get_template(template_id)
except TemplateNotFoundError:
messages.error(
request,
_('The selected configuration is no longer available. '
'Please choose another one.')
)
return redirect(reverse('hosting:index'))
data = VirtualMachineTemplateSerializer(template).data
configuration = HostingPlan.objects.get(id=configuration_id)
request.session['template'] = data
request.session['specs'] = configuration.serialize()
if not request.user.is_authenticated():
request.session['next'] = reverse('hosting:payment')
return redirect(reverse('hosting:login'))
return redirect(reverse('hosting:payment'))
class HostingContextMixin(object):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['MULTISITE_CMS_FALLBACK'] = settings.MULTISITE_CMS_FALLBACK
return context