From 8d46bd40fd9edd414cb94db686500b663ebd62ff Mon Sep 17 00:00:00 2001 From: "Ing. Jan KRCMAR" Date: Tue, 15 May 2018 14:11:31 +0200 Subject: [PATCH 1/6] create_user_block.html fix broken dom --- accounts/templates/create_user_block.html | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/accounts/templates/create_user_block.html b/accounts/templates/create_user_block.html index f4b4679..55e5c2f 100644 --- a/accounts/templates/create_user_block.html +++ b/accounts/templates/create_user_block.html @@ -1,6 +1,6 @@ {% load i18n %} {% if request.user.is_superuser %} - + @@ -8,12 +8,12 @@ From 43a8fb6dc1b52951116b28725aec5a091f51c3c1 Mon Sep 17 00:00:00 2001 From: "Ing. Jan KRCMAR" Date: Tue, 15 May 2018 14:22:10 +0200 Subject: [PATCH 2/6] add accounts view style list. configurable via settings.VIEW_ACCOUNTS_STYLE --- accounts/templates/accounts-list.html | 175 ++++++++++++++++++++++++++ accounts/views.py | 5 +- webvirtcloud/settings.py.template | 4 + 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 accounts/templates/accounts-list.html diff --git a/accounts/templates/accounts-list.html b/accounts/templates/accounts-list.html new file mode 100644 index 0000000..c6d5796 --- /dev/null +++ b/accounts/templates/accounts-list.html @@ -0,0 +1,175 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "Users" %}{% endblock %} +{% block content %} + +
+
+ {% include 'create_user_block.html' %} + +

{% trans "Users" %}

+
+
+ + + {% include 'errors_block.html' %} + +
+ {% if not users %} +
+
+ + {% trans "Warning:" %} {% trans "You don't have any User" %} +
+
+ {% else %} +
+ + + + + + + + + + + + {% for user in users %} + + + + + + + + {% endfor %} + +
UsernameStatusStaffSuperuserClone
+ {{ user.username }} + + + + + {% if user.is_active %} + {% trans "Active" %} + {% else %} + {% trans "Blocked" %} + {% endif %} + {% if user.is_staff %}{% endif %}{% if user.is_superuser %}{% endif %}{% if user.userattributes.can_clone_instances %}{% endif %}
+ + {% for user in users %} + + + {% endfor %} +
+ {% endif %} +
+{% endblock %} +{% block script %} + +{% endblock %} diff --git a/accounts/views.py b/accounts/views.py index 5fdfb4d..00bd392 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -130,7 +130,10 @@ def accounts(request): user_delete.delete() return HttpResponseRedirect(request.get_full_path()) - return render(request, 'accounts.html', locals()) + accounts_template_file = 'accounts.html' + if settings.VIEW_ACCOUNTS_STYLE == "list": + accounts_template_file = 'accounts-list.html' + return render(request, accounts_template_file, locals()) @login_required diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template index 8b0c6a7..c78ec8c 100644 --- a/webvirtcloud/settings.py.template +++ b/webvirtcloud/settings.py.template @@ -124,6 +124,10 @@ QUOTA_DEBUG = True ALLOW_EMPTY_PASSWORD = True SHOW_ACCESS_ROOT_PASSWORD = False SHOW_ACCESS_SSH_KEYS = False + +# available: default (grid), list +VIEW_ACCOUNTS_STYLE = 'grid' + SHOW_PROFILE_EDIT_PASSWORD = False INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2' INSTANCE_VOLUME_DEFAULT_BUS = 'virtio' From 82eb5abe528de428a9aeee1fcedaea8c5df634d1 Mon Sep 17 00:00:00 2001 From: "Ing. Jan KRCMAR" Date: Wed, 13 Jun 2018 10:50:36 +0200 Subject: [PATCH 3/6] add new application datasource. provides basic interface for cloud-init tool (hostname, root ssh authorized keys) --- README.md | 9 +++++ datasource/__init__.py | 0 datasource/admin.py | 3 ++ datasource/migrations/__init__.py | 0 datasource/models.py | 3 ++ datasource/templates/user_data | 6 +++ datasource/tests.py | 3 ++ datasource/urls.py | 11 ++++++ datasource/views.py | 64 +++++++++++++++++++++++++++++++ webvirtcloud/urls.py | 1 + 10 files changed, 100 insertions(+) create mode 100644 datasource/__init__.py create mode 100644 datasource/admin.py create mode 100644 datasource/migrations/__init__.py create mode 100644 datasource/models.py create mode 100644 datasource/templates/user_data create mode 100644 datasource/tests.py create mode 100644 datasource/urls.py create mode 100644 datasource/views.py diff --git a/README.md b/README.md index 8ec15f5..ae6d2c8 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ * User can add SSH public key to root in Instance (Tested only Ubuntu) * User can change root password in Instance (Tested only Ubuntu) +* Supports cloud-init datasource interface ### Warning!!! @@ -219,6 +220,14 @@ login: admin password: admin +### Cloud-init +Currently supports only root ssh authorized keys and hostname. Example configuration of the cloud-init client follows. +``` +datasource: + OpenStack: + metadata_urls: [ "http://webvirtcloud.domain.com/datasource" ] +``` + ### How To Update ```bash git pull diff --git a/datasource/__init__.py b/datasource/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/datasource/admin.py b/datasource/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/datasource/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/datasource/migrations/__init__.py b/datasource/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/datasource/models.py b/datasource/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/datasource/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/datasource/templates/user_data b/datasource/templates/user_data new file mode 100644 index 0000000..4a94483 --- /dev/null +++ b/datasource/templates/user_data @@ -0,0 +1,6 @@ +#cloud-config +{% if instance_keys %} +ssh_authorized_keys: +{% for key in instance_keys %} - {{ key }}{% endfor %} +{% endif %} + diff --git a/datasource/tests.py b/datasource/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/datasource/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/datasource/urls.py b/datasource/urls.py new file mode 100644 index 0000000..9183d41 --- /dev/null +++ b/datasource/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url +from . import views + +urlpatterns = [ + url(r'^openstack/$', + views.os_index, name='ds_openstack_index'), + url(r'^openstack/(?P[\w\-\.]+)/meta_data.json$', + views.os_metadata_json, name='ds_openstack_metadata'), + url(r'^openstack/(?P[\w\-\.]+)/user_data$', + views.os_userdata, name='ds_openstack_userdata'), +] diff --git a/datasource/views.py b/datasource/views.py new file mode 100644 index 0000000..9264717 --- /dev/null +++ b/datasource/views.py @@ -0,0 +1,64 @@ +from django.shortcuts import render +from django.http import HttpResponse, Http404 +from accounts.models import UserInstance, UserSSHKey +import json +import socket + +OS_VERSIONS = [ 'latest', '' ] +OS_UUID = "iid-dswebvirtcloud" + +def os_index(request): + response = '\n'.join(OS_VERSIONS) + return HttpResponse(response) + +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 HttpResponse(json.dumps(response)) + else: + err = 'Invalid version: %s' % version + raise Http404(err) + +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 = [] + userinstances = UserInstance.objects.filter(instance__name=vname) + + for ui in userinstances: + keys = UserSSHKey.objects.filter(user=ui.user) + for k in keys: + instance_keys.append(k.keypublic) + + return render(request, 'user_data', locals()) + else: + err = 'Invalid version: %s' % version + raise Http404(err) + +def get_client_ip(request): + 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): + addrs = socket.gethostbyaddr(ip) + return addrs[0] diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py index 8cfa9d9..e5ab3fc 100644 --- a/webvirtcloud/urls.py +++ b/webvirtcloud/urls.py @@ -9,6 +9,7 @@ urlpatterns = patterns('', url(r'^accounts/', include('accounts.urls')), url(r'^computes/', include('computes.urls')), url(r'^logs/', include('logs.urls')), + url(r'^datasource/', include('datasource.urls')), url(r'^compute/(?P[0-9]+)/storages/$', 'storages.views.storages', name='storages'), From 956b321928b69d23be2e95db9a452402795d1471 Mon Sep 17 00:00:00 2001 From: "Ing. Jan KRCMAR" Date: Wed, 13 Jun 2018 11:09:44 +0200 Subject: [PATCH 4/6] settings.py.template: add INSTALLED_APPS datasource, comment RemoteUserBackend, move SHOW_PROFILE_EDIT_PASSWORD --- webvirtcloud/settings.py.template | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template index d6d3131..eb77e8b 100644 --- a/webvirtcloud/settings.py.template +++ b/webvirtcloud/settings.py.template @@ -29,6 +29,7 @@ INSTALLED_APPS = ( 'logs', 'accounts', 'create', + 'datasource', ) MIDDLEWARE_CLASSES = ( @@ -44,6 +45,7 @@ MIDDLEWARE_CLASSES = ( AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', + #'django.contrib.auth.backends.RemoteUserBackend', #'accounts.backends.MyRemoteUserBackend', ) @@ -122,11 +124,11 @@ QUOTA_DEBUG = True ALLOW_EMPTY_PASSWORD = True SHOW_ACCESS_ROOT_PASSWORD = False SHOW_ACCESS_SSH_KEYS = False +SHOW_PROFILE_EDIT_PASSWORD = False # available: default (grid), list VIEW_ACCOUNTS_STYLE = 'grid' -SHOW_PROFILE_EDIT_PASSWORD = False INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2' INSTANCE_VOLUME_DEFAULT_BUS = 'virtio' INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync' From 6b444075b61563e15a4287c948128ce1970a6fcb Mon Sep 17 00:00:00 2001 From: Jan Krcmar Date: Wed, 13 Jun 2018 11:20:39 +0200 Subject: [PATCH 5/6] Update README.md apache configuration should use wsgi_custom.py --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae6d2c8..cd5c4e5 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ webvirtcloud RUNNING pid 24185, uptime 2:59:14 #### Apache mod_wsgi configuration ``` WSGIDaemonProcess webvirtcloud threads=2 maximum-requests=1000 display-name=webvirtcloud -WSGIScriptAlias / /srv/webvirtcloud/webvirtcloud/wsgi.py +WSGIScriptAlias / /srv/webvirtcloud/webvirtcloud/wsgi_custom.py ``` #### Install final required packages for libvirtd and others on Host Server From 22d03da60f6ba9be1b302549a69d3c8c582b2fca Mon Sep 17 00:00:00 2001 From: "Ing. Jan KRCMAR" Date: Fri, 15 Jun 2018 14:13:50 +0200 Subject: [PATCH 6/6] add views/instance/settings/vnc listen addresses configures console listen addresses for instance update webvirtcloud/settings.py QEMU_CONSOLE_LISTEN_ADDRESSES according to template, before use instances/views.py remove include webvirtcloud.settings (duplicate) --- instances/templates/instance.html | 28 ++++++++++++++++++++++++++++ instances/views.py | 14 +++++++++++--- vrtManager/instance.py | 26 ++++++++++++++++++++++++++ webvirtcloud/settings.py.template | 6 ++++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/instances/templates/instance.html b/instances/templates/instance.html index 2b73c0a..f6dc355 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -712,6 +712,27 @@ +

{% trans "To set console listen address, shutdown the instance." %}

+
{% csrf_token %} +
+ +
+ +
+
+ {% ifequal status 5 %} + + {% else %} + + {% endifequal %} +
+
+

{% trans "To create console password, shutdown the instance." %}

{% csrf_token %}
@@ -1273,6 +1294,13 @@ $("#console_select_type option[value='" + console_type + "']").prop('selected', true); } }); + $(document).ready(function () { + // set current console listen address or fall back to default + var console_listen_address = "{{ console_listen_address }}" + if (console_listen_address != '') { + $("#console_select_listen_address option[value='" + console_listen_address + "']").prop('selected', true); + } + }); {% if not request.user.is_superuser %} $('#select_clone_name').on('change', function () { update_clone_disk_name($(this).val()); diff --git a/instances/views.py b/instances/views.py index 0d6dfab..436110f 100644 --- a/instances/views.py +++ b/instances/views.py @@ -22,7 +22,6 @@ from vrtManager.connection import connection_manager from vrtManager.create import wvmCreate from vrtManager.util import randomPasswd from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE -from webvirtcloud.settings import QEMU_KEYMAPS, QEMU_CONSOLE_TYPES from logs.views import addlogmsg from django.conf import settings @@ -186,8 +185,9 @@ def instance(request, compute_id, vname): computes_count = computes.count() users = User.objects.all().order_by('username') publickeys = UserSSHKey.objects.filter(user_id=request.user.id) - keymaps = QEMU_KEYMAPS - console_types = QEMU_CONSOLE_TYPES + keymaps = settings.QEMU_KEYMAPS + console_types = settings.QEMU_CONSOLE_TYPES + console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES try: userinstace = UserInstance.objects.get(instance__compute_id=compute_id, instance__name=vname, @@ -330,6 +330,7 @@ def instance(request, compute_id, vname): console_type = conn.get_console_type() console_port = conn.get_console_port() console_keymap = conn.get_console_keymap() + console_listen_address = conn.get_console_listen_addr() snapshots = sorted(conn.get_snapshot(), reverse=True) inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE) has_managed_save_image = conn.get_managed_save_image() @@ -617,6 +618,13 @@ def instance(request, compute_id, vname): msg = _("Set VNC type") addlogmsg(request.user.username, instance.name, msg) return HttpResponseRedirect(request.get_full_path() + '#vncsettings') + + if 'set_console_listen_address' in request.POST: + console_type = request.POST.get('console_listen_address', '') + conn.set_console_listen_addr(console_type) + msg = _("Set VNC listen address") + addlogmsg(request.user.username, instance.name, msg) + return HttpResponseRedirect(request.get_full_path() + '#vncsettings') if request.user.is_superuser: if 'migrate' in request.POST: diff --git a/vrtManager/instance.py b/vrtManager/instance.py index 14feab1..72144e6 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -455,6 +455,32 @@ class wvmInstance(wvmConnect): return "127.0.0.1" return listen_addr + def set_console_listen_addr(self, listen_addr): + xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) + root = ElementTree.fromstring(xml) + console_type = self.get_console_type() + try: + graphic = root.find("devices/graphics[@type='%s']" % console_type) + except SyntaxError: + # Little fix for old version ElementTree + graphic = root.find("devices/graphics") + if graphic is None: + return False + listen = graphic.find("listen[@type='address']") + if listen is None: + return False + if listen_addr: + graphic.set("listen", listen_addr) + listen.set("address", listen_addr) + else: + try: + graphic.attrib.pop("listen") + listen.attrib.pop("address") + except: + pass + newxml = ElementTree.tostring(root) + return self._defineXML(newxml) + def get_console_socket(self): socket = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@socket") diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template index eb77e8b..b7ba1ea 100644 --- a/webvirtcloud/settings.py.template +++ b/webvirtcloud/settings.py.template @@ -106,6 +106,12 @@ QEMU_CONSOLE_TYPES = ['vnc', 'spice'] # default console type QEMU_CONSOLE_DEFAULT_TYPE = 'vnc' +# list of console listen addresses +QEMU_CONSOLE_LISTEN_ADDRESSES = ( + ('127.0.0.1', 'Localhost'), + ('0.0.0.0', 'All interfaces'), +) + # list taken from http://qemu.weilnetz.de/qemu-doc.html#sec_005finvocation QEMU_KEYMAPS = ['ar', 'da', 'de', 'de-ch', 'en-gb', 'en-us', 'es', 'et', 'fi', 'fo', 'fr', 'fr-be', 'fr-ca', 'fr-ch', 'hr', 'hu', 'is', 'it',