mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 23:25:24 +00:00
commit
3f98aa2370
9 changed files with 80 additions and 7 deletions
|
@ -32,7 +32,7 @@ print(''.join([random.SystemRandom().choice(haystack) for _ in range(50)]))
|
||||||
### Install WebVirtCloud panel (Ubuntu)
|
### Install WebVirtCloud panel (Ubuntu)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get -y install git python-virtualenv python-dev python-lxml libvirt-dev zlib1g-dev nginx supervisor libsasl2-modules gcc pkg-config python-guestfs
|
sudo apt-get -y install git python-virtualenv python-dev python-lxml libvirt-dev zlib1g-dev libxslt1-dev nginx supervisor libsasl2-modules gcc pkg-config python-guestfs
|
||||||
git clone https://github.com/retspen/webvirtcloud
|
git clone https://github.com/retspen/webvirtcloud
|
||||||
cd webvirtcloud
|
cd webvirtcloud
|
||||||
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
cp webvirtcloud/settings.py.template webvirtcloud/settings.py
|
||||||
|
|
|
@ -56,6 +56,9 @@ def profile(request):
|
||||||
if keypublic == key.keypublic:
|
if keypublic == key.keypublic:
|
||||||
msg = _("Public key already exist")
|
msg = _("Public key already exist")
|
||||||
error_messages.append(msg)
|
error_messages.append(msg)
|
||||||
|
if '\n' in keypublic or '\r' in keypublic:
|
||||||
|
msg = _("Invalid characters in public key")
|
||||||
|
error_messages.append(msg)
|
||||||
if not error_messages:
|
if not error_messages:
|
||||||
addkeypublic = UserSSHKey(user_id=request.user.id, keyname=keyname, keypublic=keypublic)
|
addkeypublic = UserSSHKey(user_id=request.user.id, keyname=keyname, keypublic=keypublic)
|
||||||
addkeypublic.save()
|
addkeypublic.save()
|
||||||
|
|
|
@ -3,3 +3,5 @@ websockify==0.8.0
|
||||||
gunicorn==19.9.0
|
gunicorn==19.9.0
|
||||||
lxml==4.2.3
|
lxml==4.2.3
|
||||||
libvirt-python==4.4.0
|
libvirt-python==4.4.0
|
||||||
|
pytz
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,6 @@ urlpatterns = [
|
||||||
views.os_metadata_json, name='ds_openstack_metadata'),
|
views.os_metadata_json, name='ds_openstack_metadata'),
|
||||||
url(r'^openstack/(?P<version>[\w\-\.]+)/user_data$',
|
url(r'^openstack/(?P<version>[\w\-\.]+)/user_data$',
|
||||||
views.os_userdata, name='ds_openstack_userdata'),
|
views.os_userdata, name='ds_openstack_userdata'),
|
||||||
|
url(r'^vdi/(?P<vname>[\w\-\.]+)/$',
|
||||||
|
views.get_vdi_url, name='vdi_url'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from accounts.models import UserInstance, UserSSHKey
|
from accounts.models import UserInstance, UserSSHKey
|
||||||
|
from instances.models import Instance
|
||||||
|
from vrtManager.instance import wvmInstance
|
||||||
|
from libvirt import libvirtError
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
@ -62,3 +65,24 @@ def get_client_ip(request):
|
||||||
def get_hostname_by_ip(ip):
|
def get_hostname_by_ip(ip):
|
||||||
addrs = socket.gethostbyaddr(ip)
|
addrs = socket.gethostbyaddr(ip)
|
||||||
return addrs[0]
|
return addrs[0]
|
||||||
|
|
||||||
|
def get_vdi_url(request, vname):
|
||||||
|
instance = Instance.objects.get(name=vname)
|
||||||
|
compute = instance.compute
|
||||||
|
data = {}
|
||||||
|
try:
|
||||||
|
conn = wvmInstance(compute.hostname,
|
||||||
|
compute.login,
|
||||||
|
compute.password,
|
||||||
|
compute.type,
|
||||||
|
instance.name)
|
||||||
|
|
||||||
|
fqdn = get_hostname_by_ip(compute.hostname)
|
||||||
|
url = "{}://{}:{}".format(conn.get_console_type(), fqdn, conn.get_console_port())
|
||||||
|
response = url
|
||||||
|
return HttpResponse(response)
|
||||||
|
|
||||||
|
except libvirtError as lib_err:
|
||||||
|
err = "Error getting vdi url for {}".format(vname)
|
||||||
|
raise Http404(err)
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<a href="{% url 'instance' compute.id vname %}" type="button" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-refresh"></span></a>
|
<a href="{% url 'instance' compute.id vname %}" type="button" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-refresh"></span></a>
|
||||||
<em>on</em>
|
<em>on</em>
|
||||||
<a href="{% url 'overview' compute.id %}"><span class="label label-primary">{{ compute.name}} - {{ compute.hostname }} </span></a>
|
<a href="{% url 'overview' compute.id %}"><span class="label label-primary">{{ compute.name }}{% if compute.name != compute.hostname %} - {{ compute.hostname }}{% endif %} </span></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if user_quota_msg %}
|
{% if user_quota_msg %}
|
||||||
|
@ -243,6 +243,13 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% ifequal status 1 %}
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="#vdiconsole" aria-controls="vdiconsole" role="tab" data-toggle="tab">
|
||||||
|
{% trans "VDI" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endifequal %}
|
||||||
</ul>
|
</ul>
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -311,6 +318,13 @@
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% ifequal status 1 %}
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vdiconsole">
|
||||||
|
<p>{% trans "This action opens a remote viewer with a connection to the console of the instance." %}</p>
|
||||||
|
<a href="#" class="btn btn-lg btn-success pull-right" id="vdi_url" >{% trans "VDI" %}</a>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -860,6 +874,10 @@
|
||||||
<button type="button" class="btn btn-sm btn-success pull-left" name="guess-clone-name"
|
<button type="button" class="btn btn-sm btn-success pull-left" name="guess-clone-name"
|
||||||
onclick="guess_clone_name()" style="margin-top: 2px;">{% trans "Guess" %}</button>
|
onclick="guess_clone_name()" style="margin-top: 2px;">{% trans "Guess" %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif clone_instance_auto_name %}
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input id="clone_instance_auto_name" type="text" class="form-control" name="auto_name" value="Automatic" disabled/>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<select id="select_clone_name" class="form-control" name="name" size="1"/>
|
<select id="select_clone_name" class="form-control" name="name" size="1"/>
|
||||||
|
@ -1027,7 +1045,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-3 control-label">{% trans "Is template" %}</label>
|
<label class="col-sm-3 control-label">{% trans "Is template" %}</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input type="checkbox" name="is_template" value="true" id="is_template" {% if instance.is_template %}checked{% endif %} {% if not request.user.is_superuser %}disabled{% endif %}>
|
<input type="checkbox" name="is_template" value="True" id="is_template" {% if instance.is_template %}checked{% endif %} {% if not request.user.is_superuser %}disabled{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% ifequal status 5 %}
|
{% ifequal status 5 %}
|
||||||
|
@ -1313,6 +1331,12 @@
|
||||||
$("#console_select_listen_address option[value='" + console_listen_address + "']").prop('selected', true);
|
$("#console_select_listen_address option[value='" + console_listen_address + "']").prop('selected', true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$(document).ready(function () {
|
||||||
|
// set vdi url
|
||||||
|
$.get("/datasource/vdi/{{ vname }}/", function(data) {
|
||||||
|
$("#vdi_url").attr("href", data);
|
||||||
|
});
|
||||||
|
});
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
random_mac(0);
|
random_mac(0);
|
||||||
|
|
|
@ -357,6 +357,7 @@ def instance(request, compute_id, vname):
|
||||||
console_type = conn.get_console_type()
|
console_type = conn.get_console_type()
|
||||||
console_port = conn.get_console_port()
|
console_port = conn.get_console_port()
|
||||||
console_keymap = conn.get_console_keymap()
|
console_keymap = conn.get_console_keymap()
|
||||||
|
console_listen_address = conn.get_console_listen_addr()
|
||||||
snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k:k['date'])
|
snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k:k['date'])
|
||||||
inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
has_managed_save_image = conn.get_managed_save_image()
|
has_managed_save_image = conn.get_managed_save_image()
|
||||||
|
@ -375,6 +376,7 @@ def instance(request, compute_id, vname):
|
||||||
default_bus = settings.INSTANCE_VOLUME_DEFAULT_BUS
|
default_bus = settings.INSTANCE_VOLUME_DEFAULT_BUS
|
||||||
show_access_root_password = settings.SHOW_ACCESS_ROOT_PASSWORD
|
show_access_root_password = settings.SHOW_ACCESS_ROOT_PASSWORD
|
||||||
show_access_ssh_keys = settings.SHOW_ACCESS_SSH_KEYS
|
show_access_ssh_keys = settings.SHOW_ACCESS_SSH_KEYS
|
||||||
|
clone_instance_auto_name = settings.CLONE_INSTANCE_AUTO_NAME
|
||||||
|
|
||||||
try:
|
try:
|
||||||
instance = Instance.objects.get(compute_id=compute_id, name=vname)
|
instance = Instance.objects.get(compute_id=compute_id, name=vname)
|
||||||
|
@ -733,6 +735,21 @@ def instance(request, compute_id, vname):
|
||||||
for post in request.POST:
|
for post in request.POST:
|
||||||
clone_data[post] = request.POST.get(post, '').strip()
|
clone_data[post] = request.POST.get(post, '').strip()
|
||||||
|
|
||||||
|
if clone_instance_auto_name and not clone_data['name']:
|
||||||
|
auto_vname = clone_free_names[0]
|
||||||
|
clone_data['name'] = auto_vname
|
||||||
|
clone_data['clone-net-mac-0'] = _get_dhcp_mac_address(auto_vname)
|
||||||
|
for post in clone_data.keys():
|
||||||
|
if post.startswith('disk-'):
|
||||||
|
disk_name = clone_data[post]
|
||||||
|
if "-" in disk_name:
|
||||||
|
suffix = disk_name.split("-")[-1]
|
||||||
|
disk_name = '-'.join((auto_vname, suffix))
|
||||||
|
else:
|
||||||
|
suffix = disk_name.split(".")[-1]
|
||||||
|
disk_name = '.'.join((auto_vname, suffix))
|
||||||
|
clone_data[post] = disk_name
|
||||||
|
|
||||||
if not request.user.is_superuser and quota_msg:
|
if not request.user.is_superuser and quota_msg:
|
||||||
msg = _("User %s quota reached, cannot create '%s'!" % (quota_msg, clone_data['name']))
|
msg = _("User %s quota reached, cannot create '%s'!" % (quota_msg, clone_data['name']))
|
||||||
error_messages.append(msg)
|
error_messages.append(msg)
|
||||||
|
|
|
@ -275,9 +275,9 @@ class wvmInstance(wvmConnect):
|
||||||
device = media.xpath('@device')[0]
|
device = media.xpath('@device')[0]
|
||||||
if device == 'cdrom':
|
if device == 'cdrom':
|
||||||
try:
|
try:
|
||||||
dev = media.xpath('target/@dev')
|
dev = media.xpath('target/@dev')[0]
|
||||||
try:
|
try:
|
||||||
src_fl = media.xpath('source/@file')
|
src_fl = media.xpath('source/@file')[0]
|
||||||
vol = self.get_volume_by_path(src_fl)
|
vol = self.get_volume_by_path(src_fl)
|
||||||
volume = vol.name()
|
volume = vol.name()
|
||||||
stg = vol.storagePoolLookupByVolume()
|
stg = vol.storagePoolLookupByVolume()
|
||||||
|
|
|
@ -133,6 +133,7 @@ LIBVIRT_KEEPALIVE_COUNT = 5
|
||||||
ALLOW_INSTANCE_MULTIPLE_OWNER = True
|
ALLOW_INSTANCE_MULTIPLE_OWNER = True
|
||||||
NEW_USER_DEFAULT_INSTANCES = []
|
NEW_USER_DEFAULT_INSTANCES = []
|
||||||
CLONE_INSTANCE_DEFAULT_PREFIX = 'instance'
|
CLONE_INSTANCE_DEFAULT_PREFIX = 'instance'
|
||||||
|
CLONE_INSTANCE_AUTO_NAME = False
|
||||||
LOGS_PER_PAGE = 100
|
LOGS_PER_PAGE = 100
|
||||||
QUOTA_DEBUG = True
|
QUOTA_DEBUG = True
|
||||||
ALLOW_EMPTY_PASSWORD = True
|
ALLOW_EMPTY_PASSWORD = True
|
||||||
|
|
Loading…
Reference in a new issue