diff --git a/README.md b/README.md index 3109bb9..aa5bc31 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ -## WebVirtCloud +## WebVirtCloud Beta + + +## Features + +* User can change root password in Virtual Machine (Tested only Ubuntu) ### Description -WebVirtMgr is a libvirt-based Web interface for managing virtual machines for admins and users. It allows you to create and configure new domains, and adjust a domain's resource allocation. A noVNC viewer presents a full graphical console to the guest domain. KVM is currently the only hypervisor supported. +WebVirtMgr is a libvirt-based Web interface for managing virtual machines. It can delegate Virtual Machine's to users. A noVNC viewer presents a full graphical console to the guest domain. KVM is currently the only hypervisor supported. ### Install WebVirtCloud panel @@ -29,7 +34,7 @@ sudo service supervisor restart ### Setup libvirt and KVM on server ```bash -wget -O - https://clck.ru/9Sz6S | sudo sh +wget -O - https://clck.ru/9V9fH | sudo sh ``` ### Default credentials diff --git a/conf/daemon/gstfsd b/conf/daemon/gstfsd new file mode 100644 index 0000000..ceb01cb --- /dev/null +++ b/conf/daemon/gstfsd @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +import SocketServer +import json +import guestfs +import re + + +PORT = 16510 +ADDRESS = "0.0.0.0" + + +class MyTCPServer(SocketServer.ThreadingTCPServer): + allow_reuse_address = True + + +class MyTCPServerHandler(SocketServer.BaseRequestHandler): + def handle(self): + # recive data + data = json.loads(self.request.recv(1024).strip()) + + # GuestFS + gfs = guestfs.GuestFS (python_return_dict=True) + try: + gfs.add_domain(data['vname']) + gfs.launch() + parts = gfs.list_partitions() + for part in parts: + try: + gfs.mount(part, '/') + if gfs.is_file('/etc/shadow'): + file_shadow = gfs.cat('/etc/shadow') + new_root_hash = "root:" + data['passwd'] + ":" + file_shadow_new = re.sub('^root:.*?:', new_root_hash, file_shadow) + gfs.write("/etc/shadow", file_shadow_new) + gfs.chmod(640, '/etc/shadow') + gfs.umount(part) + self.request.sendall(json.dumps({'return': 'success'})) + except RuntimeError: + pass + gfs.shutdown() + gfs.close() + except RuntimeError, err: + self.request.sendall(json.dumps({'return': 'error', 'message': err.message})) + +server = MyTCPServer((ADDRESS, PORT), MyTCPServerHandler) +server.serve_forever() diff --git a/conf/requirements.txt b/conf/requirements.txt new file mode 100644 index 0000000..5367e94 --- /dev/null +++ b/conf/requirements.txt @@ -0,0 +1,3 @@ +Django==1.8.1 +websockify==0.6.0 +gunicorn==19.3.0 diff --git a/conf/supervisor/gstfsd.conf b/conf/supervisor/gstfsd.conf new file mode 100644 index 0000000..2834b30 --- /dev/null +++ b/conf/supervisor/gstfsd.conf @@ -0,0 +1,7 @@ +[program:gstfsd] +command=/usr/bin/python /usr/local/bin/gstfsd +directory=/usr/local/bin +user=root +autostart=true +autorestart=true +redirect_stderr=true \ No newline at end of file diff --git a/dev/libvirt-bootstrap.sh b/dev/libvirt-bootstrap.sh index 7877811..16b252b 100644 --- a/dev/libvirt-bootstrap.sh +++ b/dev/libvirt-bootstrap.sh @@ -3,13 +3,13 @@ # vim: softtabstop=4 shiftwidth=4 expandtab fenc=utf-8 spell spelllang=en cc=81 #=============================================================================== # -# FILE: bootstrap-webvirtmgr.sh +# FILE: libvirt-bootstrap.sh # # DESCRIPTION: Bootstrap webvirtmgr installation for various distributions # -# BUGS: https://github.com/retspen/webvirtmgr-boostrap/issues +# BUGS: https://github.com/retspen/webvirtmgr/issues # -# COPYRIGHT: (c) 2013 by the WebVirtMgr Team +# COPYRIGHT: (c) 2015 by the WebVirtMgr Team # # LICENSE: Apache 2.0 # ORGANIZATION: WebVirtMgr (webvirtmgr.net) @@ -375,7 +375,7 @@ __check_end_of_life_versions # install_centos() { if [ $DISTRO_MAJOR_VERSION -ge 6 ]; then - yum -y install qemu-kvm libvirt bridge-utils || return 1 + yum -y install qemu-kvm libvirt bridge-utils python-libguestfs supervisor || return 1 fi return 0 } @@ -401,6 +401,25 @@ install_centos_post() { echoerror "/etc/libvirt/qemu.conf not found. Exiting..." exit 1 fi + if [ $DISTRO_MAJOR_VERSION -lt 7 ]; then + if [ -f /etc/supervisord.conf ]; then + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd + chmod +x /usr/local/bin/gstfsd + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf >> /etc/supervisor.conf + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi + else + if [ -f /etc/supervisord.conf ]; then + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd + chmod +x /usr/local/bin/gstfsd + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf > /etc/supervisor.d/gstfsd.ini + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi + fi return 0 } @@ -421,6 +440,14 @@ daemons_running_centos() { systemctl stop libvirt-guests.service > /dev/null 2>&1 systemctl start libvirt-guests.service fi + if [ -f /etc/init.d/supervisord ]; then + service supervisord stop > /dev/null 2>&1 + service supervisord start + fi + if [ -f /usr/lib/systemd/system/supervisord.service ]; then + systemctl stop supervisord.service > /dev/null 2>&1 + systemctl start supervisord.service + fi return 0 } # @@ -433,7 +460,7 @@ daemons_running_centos() { # Fedora Install Functions # install_fedora() { - yum -y install kvm libvirt bridge-utils || return 1 + yum -y install kvm libvirt bridge-utils python-libguestfs supervisor || return 1 return 0 } @@ -458,6 +485,14 @@ install_fedora_post() { echoerror "/etc/libvirt/qemu.conf not found. Exiting..." exit 1 fi + if [ -f /etc/supervisord.conf ]; then + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd + chmod +x /usr/local/bin/gstfsd + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf > /etc/supervisor.d/gstfsd.ini + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi return 0 } @@ -470,6 +505,10 @@ daemons_running_fedora() { systemctl stop libvirt-guests.service > /dev/null 2>&1 systemctl start libvirt-guests.service fi + if [ -f /usr/lib/systemd/system/supervisord.service ]; then + systemctl stop supervisord.service > /dev/null 2>&1 + systemctl start supervisord.service + fi return 0 } # @@ -482,7 +521,7 @@ daemons_running_fedora() { # Opensuse Install Functions # install_opensuse() { - zypper -n install -l kvm libvirt bridge-utils || return 1 + zypper -n install -l kvm libvirt bridge-utils python-libguestfs supervisor || return 1 return 0 } @@ -507,6 +546,14 @@ install_opensuse_post() { echoerror "/etc/libvirt/qemu.conf not found. Exiting..." exit 1 fi + if [ -f /etc/supervisord.conf ]; then + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd > /usr/local/bin/gstfsd + chmod +x /usr/local/bin/gstfsd + curl https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf > /etc/supervisor.d/gstfsd.ini + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi return 0 } @@ -519,6 +566,10 @@ daemons_running_opensuse() { systemctl stop libvirt-guests.service > /dev/null 2>&1 systemctl start libvirt-guests.service fi + if [ -f /usr/lib/systemd/system/supervisord.service ]; then + systemctl stop supervisord.service > /dev/null 2>&1 + systemctl start supervisord.service + fi return 0 } # @@ -532,7 +583,7 @@ daemons_running_opensuse() { # install_ubuntu() { apt-get update || return 1 - apt-get -y install kvm libvirt-bin bridge-utils sasl2-bin || return 1 + apt-get -y install kvm libvirt-bin bridge-utils sasl2-bin python-guestfs supervisor || return 1 return 0 } @@ -561,6 +612,14 @@ install_ubuntu_post() { echoerror "/etc/libvirt/qemu.conf not found. Exiting..." exit 1 fi + if [ -f /etc/supervisor/supervisord.conf ]; then + wget -O /usr/local/bin/gstfsd https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd + chmod +x /usr/local/bin/gstfsd + wget -O /etc/supervisor/conf.d/gstfsd.conf https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi return 0 } @@ -570,6 +629,11 @@ daemons_running_ubuntu() { service libvirt-bin stop > /dev/null 2>&1 service libvirt-bin start fi + if [ -f /etc/init.d/supervisor ]; then + # Still in SysV init!? + service supervisor stop > /dev/null 2>&1 + service supervisor start + fi return 0 } # @@ -583,7 +647,7 @@ daemons_running_ubuntu() { # install_debian() { apt-get update || return 1 - apt-get -y install kvm libvirt-bin bridge-utils sasl2-bin || return 1 + apt-get -y install kvm libvirt-bin bridge-utils sasl2-bin python-guestfs supervisor || return 1 return 0 } @@ -619,6 +683,14 @@ install_debian_post() { echoerror "/etc/libvirt/qemu.conf not found. Exiting..." exit 1 fi + if [ -f /etc/supervisor/supervisord.conf ]; then + wget -O /usr/local/bin/gstfsd https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/daemon/gstfsd + chmod +x /usr/local/bin/gstfsd + wget -O /etc/supervisor/conf.d/gstfsd.conf https://raw.githubusercontent.com/retspen/webvirtcloud/master/conf/supervisor/gstfsd.conf + else + echoerror "Supervisor not found. Exiting..." + exit 1 + fi return 0 } @@ -632,6 +704,10 @@ daemons_running_debian() { /etc/init.d/$LIBVIRTSVC stop > /dev/null 2>&1 /etc/init.d/$LIBVIRTSVC start fi + if [ -f /etc/init.d/supervisor ]; then + service supervisor stop > /dev/null 2>&1 + service supervisor start + fi return 0 } # diff --git a/dev/requirements.txt b/dev/requirements.txt index 580a55c..ce7c957 100644 --- a/dev/requirements.txt +++ b/dev/requirements.txt @@ -1,4 +1,4 @@ --r ../requirements.txt +-r ../conf/requirements.txt pep8==1.6.2 pyflakes==0.8.1 -pylint==1.4.3 \ No newline at end of file +pylint==1.4.3 diff --git a/instances/templates/instance.html b/instances/templates/instance.html index c9811b1..6c82eb5 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -39,6 +39,8 @@ {% include 'errors_block.html' %} + {% include 'messages_block.html' %} +
@@ -215,6 +217,11 @@ {% trans "Console" %} +
  • + + {% trans "Root Password" %} + +
  • @@ -227,6 +234,22 @@ {% endifequal %}
    +
    +

    {% trans "You need shut down your instance and enter a new root password." %}

    +
    {% csrf_token %} +
    +
    + +
    +
    + {% ifequal status 5 %} + + {% else %} + + {% endifequal %} +
    +
    +
    diff --git a/instances/templates/instances.html b/instances/templates/instances.html index fc8d00a..2dd9a37 100644 --- a/instances/templates/instances.html +++ b/instances/templates/instances.html @@ -203,7 +203,7 @@ - + {% endifequal %} diff --git a/instances/views.py b/instances/views.py index df48504..4b84f6d 100644 --- a/instances/views.py +++ b/instances/views.py @@ -1,5 +1,7 @@ import time import json +import socket +import crypt from string import letters, digits from random import choice from bisect import insort @@ -45,7 +47,7 @@ def instances(request): computes = Compute.objects.all() if not request.user.is_superuser: - user_instances = UserInstance.objects.all() + user_instances = UserInstance.objects.filter(user_id=request.user.id) for usr_inst in user_instances: if connection_manager.host_is_up(usr_inst.instance.compute.type, usr_inst.instance.compute.hostname): @@ -261,6 +263,29 @@ def instance(request, compute_id, vname): conn.delete() return HttpResponseRedirect(reverse('instances')) + if 'rootpasswd' in request.POST: + passwd = request.POST.get('passwd', '') + + passwd_hash = crypt.crypt(passwd, '$6$kgPoiREy') + data = {'passwd': passwd_hash, 'vname': vname} + + if conn.get_status() == 5: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((compute.hostname, 16510)) + s.send(json.dumps(data)) + result = json.loads(s.recv(1024)) + s.close() + msg = _("Reset root password") + addlogmsg(request.user.username, instance.name, msg) + + if result['return'] == 'success': + messages.append(msg) + else: + error_messages.append(msg) + else: + msg = _("Please shutdow down your instance and then try again") + error_messages.append(msg) + if 'resize' in request.POST: vcpu = request.POST.get('vcpu', '') cur_vcpu = request.POST.get('cur_vcpu', '') @@ -298,7 +323,7 @@ def instance(request, compute_id, vname): conn.create_snapshot(name) msg = _("New snapshot") addlogmsg(request.user.username, instance.name, msg) - return HttpResponseRedirect(request.get_full_path() + '#takesnapshot') + return HttpResponseRedirect(request.get_full_path() + '#restoresnapshot') if 'delete_snapshot' in request.POST: snap_name = request.POST.get('name', '') diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e107b2b..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -Django==1.8 -websockify==0.6.0 -gunicorn==19.3.0 \ No newline at end of file diff --git a/templates/messages_block.html b/templates/messages_block.html new file mode 100644 index 0000000..cb2aef6 --- /dev/null +++ b/templates/messages_block.html @@ -0,0 +1,14 @@ +{% if messages %} + {% for message in messages %} + +
    +
    +
    + + Success: {{ message }} +
    +
    +
    + + {% endfor %} +{% endif %} \ No newline at end of file