import socket from accounts.models import UserInstance, UserSSHKey from computes.models import Compute from django.contrib.auth.decorators import login_not_required from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponse, JsonResponse from django.shortcuts import get_object_or_404, render from instances.models import Instance from instances.utils import can_open_console from libvirt import libvirtError from vrtManager.instance import wvmInstance OS_VERSIONS = ["latest", ""] OS_UUID = "iid-dswebvirtcloud" # The cloud-init endpoints are fetched by booting VMs, which do not log in. # They expose only a hostname and the public SSH keys of a VM's owners. @login_not_required def os_index(request): """ :param request: :return: """ response = "\n".join(OS_VERSIONS) return HttpResponse(response) @login_not_required def os_metadata_json(request, version): """ :param request: :param version: :return: """ if version == "latest": ip = get_client_ip(request) hostname = get_hostname_by_ip(ip) response = {"uuid": OS_UUID, "hostname": hostname} return JsonResponse(response) else: err = "Invalid version: %(version)s" % {"version": version} raise Http404(err) @login_not_required def os_userdata(request, version): """ :param request: :param version: :return: """ if version == "latest": ip = get_client_ip(request) hostname = get_hostname_by_ip(ip) vname = hostname.split(".")[0] instance_keys = [] # VM names are not unique: with two VMs of this name, a user could put # their key into the other VM by naming theirs the same. No keys then. instances = list(Instance.objects.filter(name=vname)[:2]) if len(instances) == 1: for ui in UserInstance.objects.filter(instance=instances[0]): instance_keys += UserSSHKey.objects.filter(user=ui.user).values_list("keypublic", flat=True) return render(request, "user_data", locals()) else: err = "Invalid version: %(version)s" % {"version": version} raise Http404(err) def get_client_ip(request): """ :param request: :return: """ x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") if x_forwarded_for: ip = x_forwarded_for.split(",")[-1].strip() else: ip = request.META.get("REMOTE_ADDR") return ip def get_hostname_by_ip(ip): """ :param ip: :return: """ try: addrs = socket.gethostbyaddr(ip) except OSError: # no reverse DNS entry or an invalid address addrs = [ip] return addrs[0] def get_vdi_url(request, compute_id, vname): """ :param request: :param vname: :return: """ compute = get_object_or_404(Compute, pk=compute_id) # The VDI URL points straight at the VM's console: same rule as the console. instance = Instance.objects.filter(compute=compute, name=vname).first() if instance is None or not can_open_console(request.user, instance): raise PermissionDenied try: conn = wvmInstance( compute.hostname, compute.login, compute.password, compute.type, vname, uuid=instance.uuid ) fqdn = get_hostname_by_ip(compute.hostname) url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}" response = url return HttpResponse(response) except libvirtError: err = "Error getting VDI URL for %(name)s" % {"name": vname} raise Http404(err)