mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 15:15:22 +00:00
Merge pull request #218 from catborise/master
Boot Menu/Order Functionality And some fixes
This commit is contained in:
commit
6d178a67d8
16 changed files with 1560 additions and 766 deletions
|
@ -177,7 +177,7 @@ def compute_graph(request, compute_id):
|
||||||
datasets = {}
|
datasets = {}
|
||||||
cookies = {}
|
cookies = {}
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
curent_time = time.strftime("%H:%M:%S")
|
current_time = time.strftime("%H:%M:%S")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = wvmHostDetails(compute.hostname,
|
conn = wvmHostDetails(compute.hostname,
|
||||||
|
@ -208,7 +208,7 @@ def compute_graph(request, compute_id):
|
||||||
datasets['mem'] = eval(cookies['mem'])
|
datasets['mem'] = eval(cookies['mem'])
|
||||||
datasets['timer'] = eval(cookies['timer'])
|
datasets['timer'] = eval(cookies['timer'])
|
||||||
|
|
||||||
datasets['timer'].append(curent_time)
|
datasets['timer'].append(current_time)
|
||||||
datasets['cpu'].append(int(cpu_usage['usage']))
|
datasets['cpu'].append(int(cpu_usage['usage']))
|
||||||
datasets['mem'].append(int(mem_usage['usage']) / 1048576)
|
datasets['mem'].append(int(mem_usage['usage']) / 1048576)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Django==1.11.14
|
Django==1.11.17
|
||||||
websockify==0.8.0
|
websockify==0.8.0
|
||||||
gunicorn==19.9.0
|
gunicorn==19.9.0
|
||||||
lxml==4.2.3
|
lxml==4.2.5
|
||||||
libvirt-python==4.4.0
|
libvirt-python==4.10.0
|
||||||
pytz
|
pytz
|
||||||
|
|
||||||
|
|
|
@ -441,7 +441,7 @@
|
||||||
<label class="col-sm-3 control-label">{% trans "HDD" %}</label>
|
<label class="col-sm-3 control-label">{% trans "HDD" %}</label>
|
||||||
<input id="images" name="images" type="hidden" value=""/>
|
<input id="images" name="images" type="hidden" value=""/>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<select id="storage" name="storage" class="form-control" onchange="get_template_vols({{ compute_id }}, value);">
|
<select class="form-control" onchange="get_template_vols({{ compute_id }}, value);">
|
||||||
{% if storages %}
|
{% if storages %}
|
||||||
<option value disabled selected>{% trans "Select pool" %}...</option>
|
<option value disabled selected>{% trans "Select pool" %}...</option>
|
||||||
{% for storage in storages %}
|
{% for storage in storages %}
|
||||||
|
@ -458,6 +458,20 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Storage" %}</label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<select id="storage" name="storage" class="form-control" disabled>
|
||||||
|
{% if storages %}
|
||||||
|
{% for storage in storages %}
|
||||||
|
<option value="{{ storage }}" >{{ storage }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<option value="">{% trans "None" %}</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group meta-prealloc">
|
<div class="form-group meta-prealloc">
|
||||||
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
|
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
|
@ -697,6 +711,9 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$("#template").removeAttr("disabled");
|
$("#template").removeAttr("disabled");
|
||||||
|
$("#storage").val(pool).change();
|
||||||
|
$("#storage").removeAttr("disabled");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_disk_bus_choices(compute_id, dev_idx, disk_type){
|
function get_disk_bus_choices(compute_id, dev_idx, disk_type){
|
||||||
|
|
|
@ -134,7 +134,7 @@ def create_instance(request, compute_id):
|
||||||
error_msg = _("Image has already exist. Please check volumes or change instance name")
|
error_msg = _("Image has already exist. Please check volumes or change instance name")
|
||||||
error_messages.append(error_msg)
|
error_messages.append(error_msg)
|
||||||
else:
|
else:
|
||||||
clone_path = conn.clone_from_template(data['name'], templ_path, metadata=meta_prealloc)
|
clone_path = conn.clone_from_template(data['name'], templ_path, data['storage'], metadata=meta_prealloc)
|
||||||
volume = dict()
|
volume = dict()
|
||||||
volume['path'] = clone_path
|
volume['path'] = clone_path
|
||||||
volume['type'] = conn.get_volume_type(clone_path)
|
volume['type'] = conn.get_volume_type(clone_path)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<a href="#addvol" type="button" class="btn btn-success pull-right" data-toggle="modal">
|
<a href="#addvol" type="button" class="btn btn-success pull-right" data-toggle="modal" title="Add Volume">
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if user_quota_msg %}
|
{% if user_quota_msg %}
|
||||||
<span class="label label-warning">{{ user_quota_msg|capfirst }} quota reached.</span>
|
<span class="label label-warning">{{ user_quota_msg|capfirst }} {% trans "quota reached" %}.</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
|
@ -187,23 +187,18 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
{% ifequal status 3 %}
|
{% ifequal status 3 %}
|
||||||
{% if request.user.is_superuser %}
|
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume">
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume">
|
<form action="" method="post" role="form">{% csrf_token %}
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
<p>{% trans "This action restore the instance after suspend." %}</p>
|
<p>{% trans "This action restore the instance after suspend." %}</p>
|
||||||
<form action="" method="post" role="form">{% csrf_token %}
|
<input type="submit" name="resume" class="btn btn-lg btn-success pull-right" value="{% trans "Resume" %}">
|
||||||
<input type="submit" name="resume" class="btn btn-lg btn-success pull-right" value="{% trans "Resume" %}">
|
{% else %}
|
||||||
<div class="clearfix"></div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume">
|
|
||||||
<p>{% trans "Administrator blocked your instance." %}</p>
|
<p>{% trans "Administrator blocked your instance." %}</p>
|
||||||
<form action="" method="post" role="form">{% csrf_token %}
|
<button class="btn btn-lg btn-success disabled pull-right">{% trans "Resume" %}</button>
|
||||||
<button class="btn btn-lg btn-success disabled pull-right">{% trans "Resume" %}</button>
|
{% endif %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
{% ifequal status 5 %}
|
{% ifequal status 5 %}
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot">
|
||||||
|
@ -270,7 +265,6 @@
|
||||||
<li><a href="#" title="Console port: {{ console_port }}" onclick="open_console('full')">{% trans "Console - Full" %}</a></li>
|
<li><a href="#" title="Console port: {{ console_port }}" onclick="open_console('full')">{% trans "Console - Full" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Console" %}</button>
|
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Console" %}</button>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
@ -350,7 +344,7 @@
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resizevm">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resizevm">
|
||||||
{% if request.user.is_superuser or request.user.is_staff or userinstance.is_change %}
|
{% if request.user.is_superuser or request.user.is_staff or userinstance.is_change %}
|
||||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||||
<p style="font-weight:bold;">{% trans "Logical host CPUs:" %} {{ vcpu_host }}</p>
|
<p style="font-weight:bold;">{% trans "Logical host CPUs" %} : {{ vcpu_host }}</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-4 control-label" style="font-weight:normal;"> {% trans "Current allocation" %}</label>
|
<label class="col-sm-4 control-label" style="font-weight:normal;"> {% trans "Current allocation" %}</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
@ -381,8 +375,7 @@
|
||||||
<div class="col-sm-4 js-custom__container">
|
<div class="col-sm-4 js-custom__container">
|
||||||
<select name="cur_memory" class="form-control js-custom__toggle">
|
<select name="cur_memory" class="form-control js-custom__toggle">
|
||||||
{% for mem in memory_range %}
|
{% for mem in memory_range %}
|
||||||
<option value="{{ mem }}"
|
<option value="{{ mem }}" {% if mem == cur_memory %}selected{% endif %}>{{ mem }}</option>
|
||||||
{% if mem == cur_memory %}selected{% endif %}>{{ mem }}</option>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="text" name="cur_memory_custom" class="form-control js-custom__toggle" style="display: none" />
|
<input type="text" name="cur_memory_custom" class="form-control js-custom__toggle" style="display: none" />
|
||||||
|
@ -392,7 +385,6 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-4 control-label"
|
<label class="col-sm-4 control-label"
|
||||||
style="font-weight:normal;">{% trans "Maximum allocation" %} ({% trans "MB" %})</label>
|
style="font-weight:normal;">{% trans "Maximum allocation" %} ({% trans "MB" %})</label>
|
||||||
|
|
||||||
<div class="col-sm-4 js-custom__container">
|
<div class="col-sm-4 js-custom__container">
|
||||||
<select name="memory" class="form-control js-custom__toggle">
|
<select name="memory" class="form-control js-custom__toggle">
|
||||||
{% for mem in memory_range %}
|
{% for mem in memory_range %}
|
||||||
|
@ -425,7 +417,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -473,11 +464,11 @@
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Name" %}</th>
|
<th>{% trans "Name" %}</th>
|
||||||
<th>{% trans "Date" %}</th>
|
<th>{% trans "Date" %}</th>
|
||||||
<th colspan="2">{% trans "Action" %}</th>
|
<th colspan="2">{% trans "Action" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for snap in snapshots %}
|
{% for snap in snapshots %}
|
||||||
|
@ -526,8 +517,8 @@
|
||||||
<!-- Nav tabs -->
|
<!-- Nav tabs -->
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li role="presentation" class="active">
|
<li role="presentation" class="active">
|
||||||
<a href="#media" aria-controls="media" role="tab" data-toggle="tab">
|
<a href="#boot_opt" aria-controls="boot" role="tab" data-toggle="tab">
|
||||||
{% trans "Media" %}
|
{% trans "Boot" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
|
@ -535,13 +526,6 @@
|
||||||
{% trans "Disk" %}
|
{% trans "Disk" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<li role="presentation">
|
|
||||||
<a href="#autostart" aria-controls="autostart" role="tab" data-toggle="tab">
|
|
||||||
{% trans "Autostart" %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if request.user.is_superuser or userinstance.is_vnc %}
|
{% if request.user.is_superuser or userinstance.is_vnc %}
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
|
@ -593,78 +577,150 @@
|
||||||
</ul>
|
</ul>
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="media">
|
{% if request.user.is_superuser %}
|
||||||
{% if request.user.is_superuser and status == 5 %}
|
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot_opt">
|
||||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
<p style="font-weight:bold;">{% trans 'Autostart' %}</p>
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<button type="submit" name="add_cdrom" type="button" class="btn btn-success pull-right">
|
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
{% for cd in media %}
|
|
||||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a class="col-sm-2 control-label"
|
<div class="col-sm-12 col-sm-offset-2">
|
||||||
name="details"
|
<p>{% trans "Autostart your instance when host server is power on " %}
|
||||||
title="{% trans "Details" %}"
|
{% ifequal autostart 0 %}
|
||||||
tabindex="0"
|
<input type="submit" class="btn btn-success" name="set_autostart" value="{% trans "Enable" %}">
|
||||||
data-trigger="focus"
|
|
||||||
data-toggle="popover"
|
|
||||||
data-html="true"
|
|
||||||
data-content="<strong>Bus:</strong> {{ cd.bus }} <br/> <strong>Dev:</strong> {{ cd.dev }}">
|
|
||||||
{% trans "CDROM" %} {{ forloop.counter }}
|
|
||||||
</a>
|
|
||||||
{% if not cd.image %}
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<select name="media" class="form-control">
|
|
||||||
{% if media_iso %}
|
|
||||||
{% for iso in media_iso %}
|
|
||||||
<option value="{{ iso }}">{{ iso }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<option value="none">{% trans "None" %}</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{% if media_iso and allow_admin_or_not_template %}
|
|
||||||
<button type="submit" class="btn btn-sm btn-success pull-left" name="mount_iso" value="{{ cd.dev }}" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
|
||||||
{% if status == 5 %}
|
|
||||||
<button type="submit" class="btn btn-sm btn-danger pull-left" name="detach_cdrom" value="{{ cd.dev }}" style="margin-top: 2px;"><i class="glyphicon glyphicon-remove-circle"></i></button>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-sm btn-success pull-left disabled" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="col-sm-6">
|
<input type="submit" class="btn btn-danger" name="unset_autostart" value="{% trans "Disable" %}">
|
||||||
<input class="form-control" value="{{ cd.image }}" disabled/>
|
{% endifequal %}
|
||||||
</div>
|
</p>
|
||||||
<div class="col-sm-2">
|
</div>
|
||||||
<input type="hidden" name="path" value="{{ cd.path }}">
|
|
||||||
{% if allow_admin_or_not_template %}
|
|
||||||
<button type="submit" class="btn btn-sm btn-success pull-left" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-sm btn-success pull-left disabled" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endfor %}
|
<p style="font-weight:bold;">{% trans 'Boot Order' %}</p>
|
||||||
<div class="clearfix"></div>
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="disks">
|
<div class="col-sm-12 col-sm-offset-2">
|
||||||
<p style="font-weight:bold;">
|
{% ifequal status 5 %}
|
||||||
{% trans "Instance Volumes" %}
|
<p>{% trans "Enable Boot Menu for your instance when it starts up " %}
|
||||||
{% include 'add_instance_volume.html' %}
|
{% ifequal bootmenu 0 %}
|
||||||
</p>
|
<input type="submit" class="btn btn-success" name="set_bootmenu" title="Show boot menu" value="{% trans "Enable" %}">
|
||||||
|
{% else %}
|
||||||
|
<input type="submit" class="btn btn-danger" name="unset_bootmenu" title="Hide boot menu" value="{% trans "Disable" %}">
|
||||||
|
{% endifequal %}
|
||||||
|
{% else %}
|
||||||
|
<p>{% trans "**** Please shutdown instance to modify boot menu ****" %}
|
||||||
|
{% endifequal %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% ifequal bootmenu 1 %}
|
||||||
|
<div class="col-sm-6 col-sm-offset-2">
|
||||||
|
<div class="well">
|
||||||
|
{% for idx, val in boot_order.items %}
|
||||||
|
<label>{{ idx|add:1 }}:{{ val.target }}, </label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
|
<input id="bootorder" name="bootorder" hidden>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-6 col-sm-offset-2">
|
||||||
|
<div id="b_order" class="multiselect">
|
||||||
|
{% for disk in disks %}
|
||||||
|
<label><input type="checkbox" name="disk:{{ disk.dev }}" value="disk:{{ disk.dev }}" onclick="set_orderlist($('#bootorder'))" />{{ disk.dev }} - {{ disk.image }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
{% for cd in media %}
|
||||||
|
<label><input type="checkbox" name="cdrom:{{ cd.dev }}" value="cdrom:{{ cd.dev }}" onclick="set_orderlist($('#bootorder'))"/>{{ cd.dev }} - {{ cd.image }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
{% for net in networks %}
|
||||||
|
<label><input type="checkbox" name="network:{{ net.mac }}" value="network:{{ net.mac }}" onclick="set_orderlist($('#bootorder'))"/>NIC - {{ net.mac|slice:"9:" }}</label>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="row" style="margin-top: 2em;">
|
||||||
|
<a href="#" id="boot_order_up" class="btn btn-default"><span class="glyphicon glyphicon-arrow-up" title="up: move selected devices"></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="margin-top: 1em;">
|
||||||
|
<a href="#" id="boot_order_down" class="btn btn-default"><span class="glyphicon glyphicon-arrow-down" title="down: move selected devices"></span></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-sm-offset-2">
|
||||||
|
<input type="submit" class="btn btn-success btn-block" name="set_bootorder" value="{% trans "Apply" %}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endifequal %}
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="disks">
|
||||||
|
{% if status == 5 %}
|
||||||
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
|
<p style="font-weight:bold;">
|
||||||
|
{% trans "Instance Media" %}
|
||||||
|
<button type="submit" name="add_cdrom" type="button" class="btn btn-success pull-right" title="Add CD-Rom">
|
||||||
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% for cd in media %}
|
||||||
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
|
<div class="form-group">
|
||||||
|
<a class="col-sm-3 control-label"
|
||||||
|
name="details"
|
||||||
|
title="{% trans "Details" %}"
|
||||||
|
tabindex="0"
|
||||||
|
data-trigger="focus"
|
||||||
|
data-toggle="popover"
|
||||||
|
data-html="true"
|
||||||
|
data-content="<strong>{% trans 'Bus' %}:</strong> {{ cd.bus }} <br/>
|
||||||
|
<strong>{% trans 'Dev' %}:</strong> {{ cd.dev }}">
|
||||||
|
{% trans "CDROM" %} {{ forloop.counter }}
|
||||||
|
</a>
|
||||||
|
{% if not cd.image %}
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select name="media" class="form-control">
|
||||||
|
{% if media_iso %}
|
||||||
|
{% for iso in media_iso %}
|
||||||
|
<option value="{{ iso }}">{{ iso }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<option value="none">{% trans "None" %}</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
{% if media_iso and allow_admin_or_not_template %}
|
||||||
|
<button type="submit" class="btn btn-sm btn-success pull-left" name="mount_iso" value="{{ cd.dev }}" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-sm btn-success pull-left disabled" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if status == 5 and allow_admin_or_not_template %}
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger pull-left" title="Detach CD-Rom (remove device)" name="detach_cdrom" value="{{ cd.dev }}" style="margin-top: 2px;"><i class="glyphicon glyphicon-remove-circle"></i></button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input class="form-control" value="{{ cd.image }}" disabled/>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="hidden" name="path" value="{{ cd.path }}">
|
||||||
|
{% if allow_admin_or_not_template %}
|
||||||
|
<button type="submit" class="btn btn-sm btn-success pull-left" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-sm btn-success pull-left disabled" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="col-xs-12 col-sm-12">
|
<p style="font-weight:bold;">
|
||||||
|
{% trans "Instance Volume" %}
|
||||||
|
{% include 'add_instance_volume.html' %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-12">
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<th>{% trans "Device" %}</th>
|
<th>{% trans "Device" %}</th>
|
||||||
|
@ -685,7 +741,9 @@
|
||||||
data-trigger="focus"
|
data-trigger="focus"
|
||||||
data-toggle="popover"
|
data-toggle="popover"
|
||||||
data-html="true"
|
data-html="true"
|
||||||
data-content="<strong>Bus:</strong> {{ disk.bus }} <br/> <strong>Format:</strong> {{ disk.format }}">
|
data-content="<strong>Bus:</strong> {{ disk.bus }} <br/>
|
||||||
|
<strong>Format:</strong> {{ disk.format }} <br/>
|
||||||
|
<strong>Cache:</strong> {{ disk.cache }}">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-info"></i>
|
||||||
</button>
|
</button>
|
||||||
{{ disk.dev }}
|
{{ disk.dev }}
|
||||||
|
@ -724,21 +782,167 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="network">
|
||||||
|
<p>
|
||||||
|
{% trans "Assign network device to bridge" %}
|
||||||
|
{% include 'add_instance_network_block.html' %}
|
||||||
|
</p>
|
||||||
|
<p style="font-weight:bold;">{% trans "Network devices" %}</p>
|
||||||
|
<div class="col-xs-12 col-sm-12">
|
||||||
|
<form method="post" role="form">{% csrf_token %}
|
||||||
|
{% for network in networks %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<label>eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "MAC" %} </label>
|
||||||
|
<input class="form-control" type="text" value="{{ network.mac }}" readonly/>
|
||||||
|
<label class="control-label"><em>to</em></label>
|
||||||
|
<input class="form-control" type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "NIC" %} </label>
|
||||||
|
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
||||||
|
<label class="control-label"><em>to</em></label>
|
||||||
|
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
||||||
|
{% for c_net in compute_networks %}
|
||||||
|
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>Network {{ c_net }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% for c_iface in compute_interfaces %}
|
||||||
|
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>Interface {{ c_iface }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<label class="col-sm-2 col-sm-offset-1">{% trans "Filter" %} </label>
|
||||||
|
<input class="form-control" type="text" value="{{ network.filterref }}" readonly/>
|
||||||
|
<label class="control-label"><em>to</em></label>
|
||||||
|
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
|
||||||
|
<option value="">{% trans "None" %}</option>
|
||||||
|
{% for c_filters in compute_nwfilters %}
|
||||||
|
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if request.user.is_superuser %}
|
<div class="panel-footer">
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="autostart">
|
<button class="btn btn-sm btn-primary" name="change_network" title="{% trans "Change" %}">{% trans "Change" %}</button>
|
||||||
<p>{% trans "Autostart your instance when host server is power on" %}</p>
|
<button class="btn btn-sm pull-right btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">{% trans "Delete" %}</button>
|
||||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
</div>
|
||||||
{% ifequal autostart 0 %}
|
</div>
|
||||||
<input type="submit" class="btn btn-lg btn-success pull-right" name="set_autostart" value="{% trans "Enable" %}">
|
{% endfor %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="migrate">
|
||||||
|
<p>{% trans "For migration both host servers must have equal settings and OS type" %}</p>
|
||||||
|
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Original host" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p style="margin: 10px -10px 0 0;">{{ compute.name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Host migration" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select name="compute_id" class="form-control">
|
||||||
|
{% if computes_count != 1 %}
|
||||||
|
{% for comp in computes %}
|
||||||
|
{% if comp.id != compute.id %}
|
||||||
|
<option value="{{ comp.id }}">{{ comp.name }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Live migration" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% ifequal status 1 %}checked{% endifequal %}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Unsafe migration" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="checkbox" name="unsafe_migrate" value="true" id="vm_unsafe_migrate">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Delete original" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="checkbox" name="xml_delete" value="true" id="xml_delete" checked>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">{% trans "Offline migration" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% ifequal status 5 %}checked{% endifequal %}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if computes_count != 1 %}
|
||||||
|
<button type="submit" class="btn btn-lg btn-success pull-right" name="migrate" onclick="showPleaseWaitDialog();">{% trans "Migrate" %}</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="submit" class="btn btn-lg btn-success pull-right" name="unset_autostart" value="{% trans "Disable" %}">
|
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Migrate" %}</button>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
<div class="clearfix"></div></p>
|
||||||
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="xmledit">
|
||||||
|
<p>{% trans "If you need to edit xml please Power Off the instance" %}</p>
|
||||||
|
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||||
|
<div class="col-sm-12" id="xmlheight">
|
||||||
|
<textarea id="editor">{{ inst_xml }}</textarea>
|
||||||
|
</div>
|
||||||
|
{% ifequal status 5 %}
|
||||||
|
<input type="hidden" name="inst_xml">
|
||||||
|
<button type="submit" class="btn btn-lg btn-success pull-right" name="change_xml">
|
||||||
|
{% trans "Change" %}
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-lg btn-success pull-right disabled">
|
||||||
|
{% trans "Change" %}
|
||||||
|
</button>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
</form>
|
</form>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="users">
|
||||||
|
<div>
|
||||||
|
<p style="font-weight:bold;">
|
||||||
|
{% trans "Instance owners" %}
|
||||||
|
{% include 'add_instance_owner_block.html' %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped sortable-theme-bootstrap" data-sortable>
|
||||||
|
<tbody class="searchable">
|
||||||
|
{% for userinstance in userinstances %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'account' userinstance.user.id %}">{{ userinstance.user }}</a></td>
|
||||||
|
<td style="width:30px;">
|
||||||
|
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||||
|
<input type="hidden" name="userinstance" value="{{ userinstance.pk }}">
|
||||||
|
<button type="submit" class="btn btn-sm btn-default" name="del_owner" title="{% trans "Delete" %}">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser or userinstance.is_vnc %}
|
{% if request.user.is_superuser or userinstance.is_vnc %}
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vncsettings">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vncsettings">
|
||||||
|
@ -855,65 +1059,6 @@
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="network">
|
|
||||||
<p>
|
|
||||||
{% trans "Assign network device to bridge" %}
|
|
||||||
{% include 'add_instance_network_block.html' %}
|
|
||||||
</p>
|
|
||||||
<p style="font-weight:bold;">{% trans "Network devices" %}</p>
|
|
||||||
<div class="col-xs-12 col-sm-12">
|
|
||||||
<form method="post" role="form">{% csrf_token %}
|
|
||||||
{% for network in networks %}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<label>eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "MAC" %} </label>
|
|
||||||
<input class="form-control" type="text" value="{{ network.mac }}" readonly/>
|
|
||||||
<label class="control-label"><em>to</em></label>
|
|
||||||
<input class="form-control" type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "NIC" %} </label>
|
|
||||||
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
|
||||||
<label class="control-label"><em>to</em></label>
|
|
||||||
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
|
||||||
{% for c_net in compute_networks %}
|
|
||||||
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>Network {{ c_net }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
{% for c_iface in compute_interfaces %}
|
|
||||||
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>Interface {{ c_iface }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<label class="col-sm-2 col-sm-offset-1">{% trans "Filter" %} </label>
|
|
||||||
<input class="form-control" type="text" value="{{ network.filterref }}" readonly/>
|
|
||||||
<label class="control-label"><em>to</em></label>
|
|
||||||
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
|
|
||||||
<option value="">{% trans "None" %}</option>
|
|
||||||
{% for c_filters in compute_nwfilters %}
|
|
||||||
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-footer">
|
|
||||||
<button class="btn btn-sm btn-primary" name="change_network" title="{% trans "Change" %}">{% trans "Change" %}</button>
|
|
||||||
<button class="btn btn-sm pull-right btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">{% trans "Delete" %}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if request.user.is_superuser or request.user.userattributes.can_clone_instances %}
|
{% if request.user.is_superuser or request.user.userattributes.can_clone_instances %}
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="clone">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="clone">
|
||||||
<p style="font-weight:bold;">{% trans "Create a clone" %}</p>
|
<p style="font-weight:bold;">{% trans "Create a clone" %}</p>
|
||||||
|
@ -921,25 +1066,25 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Clone Name" %}</label>
|
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Clone Name" %}</label>
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input id="clone_name" type="text" class="form-control" name="name" value="{{ vname }}-clone"/>
|
<input id="clone_name" type="text" class="form-control" name="name" value="{{ vname }}-clone"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<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 %}
|
{% elif clone_instance_auto_name %}
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input id="clone_instance_auto_name" type="text" class="form-control" name="auto_name" value="Automatic" disabled/>
|
<input id="clone_instance_auto_name" type="text" class="form-control" name="auto_name" value="Automatic" disabled/>
|
||||||
</div>
|
</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"/>
|
||||||
{% for name in clone_free_names %}
|
{% for name in clone_free_names %}
|
||||||
<option value="{{ name }}">{{ name }}</option>
|
<option value="{{ name }}">{{ name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
|
@ -1004,84 +1149,6 @@
|
||||||
</form>
|
</form>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="migrate">
|
|
||||||
<p>{% trans "For migration both host servers must have equal settings and OS type" %}</p>
|
|
||||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Original host" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<p style="margin: 10px -10px 0 0;">{{ compute.name }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Host migration" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<select name="compute_id" class="form-control">
|
|
||||||
{% if computes_count != 1 %}
|
|
||||||
{% for comp in computes %}
|
|
||||||
{% if comp.id != compute.id %}
|
|
||||||
<option value="{{ comp.id }}">{{ comp.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Live migration" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% ifequal status 1 %}checked{% endifequal %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Unsafe migration" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="checkbox" name="unsafe_migrate" value="true" id="vm_unsafe_migrate">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Delete original" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="checkbox" name="xml_delete" value="true" id="xml_delete" checked>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label">{% trans "Offline migration" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% ifequal status 5 %}checked{% endifequal %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if computes_count != 1 %}
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="migrate" onclick="showPleaseWaitDialog();">{% trans "Migrate" %}</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Migrate" %}</button>
|
|
||||||
{% endif %}
|
|
||||||
</form>
|
|
||||||
<div class="clearfix"></div></p>
|
|
||||||
</div>
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="xmledit">
|
|
||||||
<p>{% trans "If you need to edit xml please Power Off the instance" %}</p>
|
|
||||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
|
||||||
<div class="col-sm-12" id="xmlheight">
|
|
||||||
<textarea id="editor">{{ inst_xml }}</textarea>
|
|
||||||
</div>
|
|
||||||
{% ifequal status 5 %}
|
|
||||||
<input type="hidden" name="inst_xml">
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="change_xml">
|
|
||||||
{% trans "Change" %}
|
|
||||||
</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">
|
|
||||||
{% trans "Change" %}
|
|
||||||
</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</form>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if request.user.is_superuser or request.user.userattributes.can_clone_instances %}
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="options">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="options">
|
||||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -1111,36 +1178,6 @@
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="users">
|
|
||||||
<div>
|
|
||||||
<p style="font-weight:bold;">
|
|
||||||
{% trans "Instance owners" %}
|
|
||||||
{% include 'add_instance_owner_block.html' %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable>
|
|
||||||
<tbody class="searchable">
|
|
||||||
{% for userinstance in userinstances %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'account' userinstance.user.id %}">{{ userinstance.user }}</a></td>
|
|
||||||
<td style="width:30px;">
|
|
||||||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
|
||||||
<input type="hidden" name="userinstance" value="{{ userinstance.pk }}">
|
|
||||||
<button type="submit" class="btn btn-sm btn-default" name="del_owner" title="{% trans "Delete" %}">
|
|
||||||
<i class="fa fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1215,7 +1252,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="searchable">
|
<tbody class="searchable">
|
||||||
<tr><td colspan="3"><i>None ...</i></td></tr>
|
<tr><td colspan="3"><i>{% trans 'None' %}...</i></td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1269,8 +1306,6 @@
|
||||||
<script src="{% static "js/ace.js" %}" type="text/javascript" charset="utf-8"></script>
|
<script src="{% static "js/ace.js" %}" type="text/javascript" charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
function get_volumes(compute_id, pool) {
|
function get_volumes(compute_id, pool) {
|
||||||
|
|
||||||
|
|
||||||
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
||||||
$.getJSON(get_vol_url, function (data) {
|
$.getJSON(get_vol_url, function (data) {
|
||||||
$("#vols").find('option').remove();
|
$("#vols").find('option').remove();
|
||||||
|
@ -1279,8 +1314,7 @@
|
||||||
$.each(data['vols'], function(i, item) {
|
$.each(data['vols'], function(i, item) {
|
||||||
$("#vols").append('<option value=' + item +'>' + item + '</option>');
|
$("#vols").append('<option value=' + item +'>' + item + '</option>');
|
||||||
|
|
||||||
});
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var sto_drop = document.getElementById('select_storage');
|
var sto_drop = document.getElementById('select_storage');
|
||||||
|
@ -1290,7 +1324,6 @@
|
||||||
var sto_input = document.getElementById('selected_storage');
|
var sto_input = document.getElementById('selected_storage');
|
||||||
sto_input.value = pool;
|
sto_input.value = pool;
|
||||||
sto_input.innerHTML = pool;
|
sto_input.innerHTML = pool;
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1413,7 +1446,6 @@
|
||||||
});
|
});
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// set vdi url
|
// set vdi url
|
||||||
|
|
||||||
$.get("{% url 'vdi_url' vname %}", function(data) {
|
$.get("{% url 'vdi_url' vname %}", function(data) {
|
||||||
$("#vdi_url_input").attr("value", data);
|
$("#vdi_url_input").attr("value", data);
|
||||||
$("#vdi_url").attr("href", data);
|
$("#vdi_url").attr("href", data);
|
||||||
|
@ -1443,6 +1475,69 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
function set_orderlist(obj){
|
||||||
|
var result = '';
|
||||||
|
$('#b_order label input:checked').each(function () {
|
||||||
|
if (result != '') result += ',';
|
||||||
|
result += $(this).val();
|
||||||
|
});
|
||||||
|
obj.val(result);
|
||||||
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
{# Boot Order Arragements #}
|
||||||
|
jQuery.fn.multiselect = function() {
|
||||||
|
$(this).each(function() {
|
||||||
|
var checkboxes = $(this).find("input:checkbox");
|
||||||
|
checkboxes.each(function() {
|
||||||
|
var checkbox = $(this);
|
||||||
|
// Highlight pre-selected checkboxes
|
||||||
|
if (checkbox.prop("checked"))
|
||||||
|
checkbox.parent().addClass("multiselect-on");
|
||||||
|
// Highlight checkboxes that the user selects
|
||||||
|
checkbox.click(function() {
|
||||||
|
if (checkbox.prop("checked"))
|
||||||
|
checkbox.parent().addClass("multiselect-on");
|
||||||
|
else
|
||||||
|
checkbox.parent().removeClass("multiselect-on");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$(function() {
|
||||||
|
$(".multiselect").multiselect();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#boot_order_up').bind('click', function() {
|
||||||
|
$('#b_order label input:checked').each( function() {
|
||||||
|
var label = $(this).parent();
|
||||||
|
var newPos = label.index() - 1;
|
||||||
|
if (newPos > -1) {
|
||||||
|
$('#b_order label').eq(newPos).before("<label><input type='checkbox' value='"+$(this).val()+"' name='"+$(this).val()+"' checked>"+$(this).parent().text()+"</label>");
|
||||||
|
label.remove();
|
||||||
|
}
|
||||||
|
$(".multiselect").multiselect();
|
||||||
|
});
|
||||||
|
set_orderlist($("#bootorder"));
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#boot_order_down').bind('click', function() {
|
||||||
|
var countOptions = $('#b_order label').size();
|
||||||
|
var countSelected = $('#b_order label input:checked').size();
|
||||||
|
$('#b_order label input:checked').each( function() {
|
||||||
|
var label = $(this).parent();
|
||||||
|
var newPos = label.index() + countSelected;
|
||||||
|
if (newPos < countOptions) {
|
||||||
|
$('#b_order label').eq(newPos).after("<label><input type='checkbox' value='"+$(this).val()+"' name='"+$(this).val()+"' checked>"+$(this).parent().text()+"</label>");
|
||||||
|
label.remove();
|
||||||
|
}
|
||||||
|
$(".multiselect").multiselect();
|
||||||
|
});
|
||||||
|
set_orderlist($("#bootorder"));
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('.js-custom__checkbox').change(function () {
|
$('.js-custom__checkbox').change(function () {
|
||||||
|
@ -1617,7 +1712,7 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (~$.inArray(hash, ['#media', "#disks", '#network', '#clone', '#autostart', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
|
if (~$.inArray(hash, ['#boot_opt', "#disks", '#network', '#clone', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
|
||||||
var btnsect = $('#navbtn>li>a');
|
var btnsect = $('#navbtn>li>a');
|
||||||
$(btnsect).each(function () {
|
$(btnsect).each(function () {
|
||||||
if ($(this).attr('href') === '#settings') {
|
if ($(this).attr('href') === '#settings') {
|
||||||
|
|
|
@ -52,16 +52,16 @@ def allinstances(request):
|
||||||
else:
|
else:
|
||||||
for comp in computes:
|
for comp in computes:
|
||||||
try:
|
try:
|
||||||
all_host_vms.update(get_host_instances(request,comp))
|
all_host_vms.update(get_host_instances(request, comp))
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
error_messages.append(lib_err)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
try:
|
try:
|
||||||
instances_actions(request)
|
return instances_actions(request)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
error_messages.append(lib_err)
|
||||||
addlogmsg(request.user.username, instance.name, lib_err.message)
|
addlogmsg(request.user.username, request.POST.get("name", "instance"), lib_err.message)
|
||||||
|
|
||||||
view_style = settings.VIEW_INSTANCES_LIST_STYLE
|
view_style = settings.VIEW_INSTANCES_LIST_STYLE
|
||||||
|
|
||||||
|
@ -88,10 +88,10 @@ def instances(request, compute_id):
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
try:
|
try:
|
||||||
instances_actions(request)
|
return instances_actions(request)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
error_messages.append(lib_err)
|
||||||
addlogmsg(request.user.username, instance.name, lib_err.message)
|
addlogmsg(request.user.username, request.POST.get("name", "instance"), lib_err.message)
|
||||||
|
|
||||||
return render(request, 'instances.html', locals())
|
return render(request, 'instances.html', locals())
|
||||||
|
|
||||||
|
@ -255,6 +255,8 @@ def instance(request, compute_id, vname):
|
||||||
compute_nwfilters = conn.get_nwfilters()
|
compute_nwfilters = conn.get_nwfilters()
|
||||||
status = conn.get_status()
|
status = conn.get_status()
|
||||||
autostart = conn.get_autostart()
|
autostart = conn.get_autostart()
|
||||||
|
bootmenu = conn.get_bootmenu()
|
||||||
|
boot_order = conn.get_bootorder()
|
||||||
vcpu = conn.get_vcpu()
|
vcpu = conn.get_vcpu()
|
||||||
cur_vcpu = conn.get_cur_vcpu()
|
cur_vcpu = conn.get_cur_vcpu()
|
||||||
uuid = conn.get_uuid()
|
uuid = conn.get_uuid()
|
||||||
|
@ -525,7 +527,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.attach_disk("", target, device='cdrom', cache='none', targetbus=bus)
|
conn.attach_disk("", target, device='cdrom', cache='none', targetbus=bus)
|
||||||
msg = _('Add CD-Rom: ' + target)
|
msg = _('Add CD-Rom: ' + target)
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||||
|
|
||||||
if 'detach_cdrom' in request.POST and allow_admin_or_not_template:
|
if 'detach_cdrom' in request.POST and allow_admin_or_not_template:
|
||||||
dev = request.POST.get('detach_cdrom', '')
|
dev = request.POST.get('detach_cdrom', '')
|
||||||
|
@ -533,7 +535,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.detach_disk(dev)
|
conn.detach_disk(dev)
|
||||||
msg = _('Detach CD-Rom: ' + dev)
|
msg = _('Detach CD-Rom: ' + dev)
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||||
|
|
||||||
if 'umount_iso' in request.POST and allow_admin_or_not_template:
|
if 'umount_iso' in request.POST and allow_admin_or_not_template:
|
||||||
image = request.POST.get('path', '')
|
image = request.POST.get('path', '')
|
||||||
|
@ -541,7 +543,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.umount_iso(dev, image)
|
conn.umount_iso(dev, image)
|
||||||
msg = _("Mount media: " + dev)
|
msg = _("Mount media: " + dev)
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||||
|
|
||||||
if 'mount_iso' in request.POST and allow_admin_or_not_template:
|
if 'mount_iso' in request.POST and allow_admin_or_not_template:
|
||||||
image = request.POST.get('media', '')
|
image = request.POST.get('media', '')
|
||||||
|
@ -549,7 +551,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.mount_iso(dev, image)
|
conn.mount_iso(dev, image)
|
||||||
msg = _("Umount media: " + dev)
|
msg = _("Umount media: " + dev)
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||||
|
|
||||||
if 'snapshot' in request.POST and allow_admin_or_not_template:
|
if 'snapshot' in request.POST and allow_admin_or_not_template:
|
||||||
name = request.POST.get('name', '')
|
name = request.POST.get('name', '')
|
||||||
|
@ -591,13 +593,37 @@ def instance(request, compute_id, vname):
|
||||||
conn.set_autostart(1)
|
conn.set_autostart(1)
|
||||||
msg = _("Set autostart")
|
msg = _("Set autostart")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#autostart')
|
return HttpResponseRedirect(request.get_full_path() + '#boot_opt')
|
||||||
|
|
||||||
if 'unset_autostart' in request.POST:
|
if 'unset_autostart' in request.POST:
|
||||||
conn.set_autostart(0)
|
conn.set_autostart(0)
|
||||||
msg = _("Unset autostart")
|
msg = _("Unset autostart")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#autostart')
|
return HttpResponseRedirect(request.get_full_path() + '#boot_opt')
|
||||||
|
|
||||||
|
if 'set_bootmenu' in request.POST:
|
||||||
|
conn.set_bootmenu(1)
|
||||||
|
msg = _("Enable boot menu")
|
||||||
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#boot_opt')
|
||||||
|
|
||||||
|
if 'unset_bootmenu' in request.POST:
|
||||||
|
conn.set_bootmenu(0)
|
||||||
|
msg = _("Disable boot menu")
|
||||||
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#boot_opt')
|
||||||
|
|
||||||
|
if 'set_bootorder' in request.POST:
|
||||||
|
bootorder = request.POST.get('bootorder', '')
|
||||||
|
if bootorder:
|
||||||
|
order_list = {}
|
||||||
|
for idx, val in enumerate(bootorder.split(',')):
|
||||||
|
type, dev = val.split(':', 1)
|
||||||
|
order_list[idx] = {"type": type, "dev": dev}
|
||||||
|
conn.set_bootorder(order_list)
|
||||||
|
msg = _("Set boot order")
|
||||||
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#boot_opt')
|
||||||
|
|
||||||
if 'change_xml' in request.POST:
|
if 'change_xml' in request.POST:
|
||||||
exit_xml = request.POST.get('inst_xml', '')
|
exit_xml = request.POST.get('inst_xml', '')
|
||||||
|
@ -802,7 +828,6 @@ def instance(request, compute_id, vname):
|
||||||
msg = _("Edit options")
|
msg = _("Edit options")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#options')
|
return HttpResponseRedirect(request.get_full_path() + '#options')
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
|
@ -837,7 +862,7 @@ def inst_status(request, compute_id, vname):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get_host_instances(request,comp):
|
def get_host_instances(request, comp):
|
||||||
|
|
||||||
def refresh_instance_database(comp, inst_name, info):
|
def refresh_instance_database(comp, inst_name, info):
|
||||||
def get_userinstances_info(instance):
|
def get_userinstances_info(instance):
|
||||||
|
@ -883,7 +908,6 @@ def get_host_instances(request,comp):
|
||||||
status = connection_manager.host_is_up(comp.type, comp.hostname)
|
status = connection_manager.host_is_up(comp.type, comp.hostname)
|
||||||
|
|
||||||
if status:
|
if status:
|
||||||
|
|
||||||
conn = wvmHostDetails(comp, comp.login, comp.password, comp.type)
|
conn = wvmHostDetails(comp, comp.login, comp.password, comp.type)
|
||||||
comp_node_info = conn.get_node_info()
|
comp_node_info = conn.get_node_info()
|
||||||
comp_mem = conn.get_memory_usage()
|
comp_mem = conn.get_memory_usage()
|
||||||
|
@ -907,6 +931,7 @@ def get_host_instances(request,comp):
|
||||||
|
|
||||||
return all_host_vms
|
return all_host_vms
|
||||||
|
|
||||||
|
|
||||||
def get_user_instances(request):
|
def get_user_instances(request):
|
||||||
all_user_vms = {}
|
all_user_vms = {}
|
||||||
user_instances = UserInstance.objects.filter(user_id=request.user.id)
|
user_instances = UserInstance.objects.filter(user_id=request.user.id)
|
||||||
|
@ -975,7 +1000,6 @@ def instances_actions(request):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
|
|
||||||
if 'suspend' in request.POST:
|
if 'suspend' in request.POST:
|
||||||
msg = _("Suspend")
|
msg = _("Suspend")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
@ -1003,7 +1027,7 @@ def inst_graph(request, compute_id, vname):
|
||||||
datasets_net = {}
|
datasets_net = {}
|
||||||
cookies = {}
|
cookies = {}
|
||||||
points = 5
|
points = 5
|
||||||
curent_time = time.strftime("%H:%M:%S")
|
current_time = time.strftime("%H:%M:%S")
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
response['Content-Type'] = "text/javascript"
|
response['Content-Type'] = "text/javascript"
|
||||||
|
@ -1030,18 +1054,15 @@ def inst_graph(request, compute_id, vname):
|
||||||
cookies['net'] = request.COOKIES['net']
|
cookies['net'] = request.COOKIES['net']
|
||||||
cookies['timer'] = request.COOKIES['timer']
|
cookies['timer'] = request.COOKIES['timer']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
cookies['cpu'] = None
|
cookies['cpu'] = cookies['blk'] = cookies['net'] = None
|
||||||
cookies['blk'] = None
|
|
||||||
cookies['net'] = None
|
|
||||||
|
|
||||||
if not cookies['cpu']:
|
if not cookies['cpu']:
|
||||||
datasets['cpu'] = [0] * points
|
datasets['timer'] = datasets['cpu'] = [0] * points
|
||||||
datasets['timer'] = [0] * points
|
|
||||||
else:
|
else:
|
||||||
datasets['cpu'] = eval(cookies['cpu'])
|
datasets['cpu'] = eval(cookies['cpu'])
|
||||||
datasets['timer'] = eval(cookies['timer'])
|
datasets['timer'] = eval(cookies['timer'])
|
||||||
|
|
||||||
datasets['timer'].append(curent_time)
|
datasets['timer'].append(current_time)
|
||||||
datasets['cpu'].append(int(cpu_usage['cpu']))
|
datasets['cpu'].append(int(cpu_usage['cpu']))
|
||||||
|
|
||||||
datasets['timer'] = check_points(datasets['timer'])
|
datasets['timer'] = check_points(datasets['timer'])
|
||||||
|
@ -1049,8 +1070,7 @@ def inst_graph(request, compute_id, vname):
|
||||||
|
|
||||||
for blk in blk_usage:
|
for blk in blk_usage:
|
||||||
if not cookies['blk']:
|
if not cookies['blk']:
|
||||||
datasets_wr = [0] * points
|
datasets_rd = datasets_wr = [0] * points
|
||||||
datasets_rd = [0] * points
|
|
||||||
else:
|
else:
|
||||||
datasets['blk'] = eval(cookies['blk'])
|
datasets['blk'] = eval(cookies['blk'])
|
||||||
datasets_rd = datasets['blk'][blk['dev']][0]
|
datasets_rd = datasets['blk'][blk['dev']][0]
|
||||||
|
@ -1067,8 +1087,7 @@ def inst_graph(request, compute_id, vname):
|
||||||
|
|
||||||
for net in net_usage:
|
for net in net_usage:
|
||||||
if not cookies['net']:
|
if not cookies['net']:
|
||||||
datasets_rx = [0] * points
|
datasets_tx = datasets_rx = [0] * points
|
||||||
datasets_tx = [0] * points
|
|
||||||
else:
|
else:
|
||||||
datasets['net'] = eval(cookies['net'])
|
datasets['net'] = eval(cookies['net'])
|
||||||
datasets_rx = datasets['net'][net['dev']][0]
|
datasets_rx = datasets['net'][net['dev']][0]
|
||||||
|
@ -1133,7 +1152,7 @@ def _get_random_mac_address():
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def random_mac_address(request):
|
def random_mac_address(request):
|
||||||
data = {}
|
data = dict()
|
||||||
data['mac'] = _get_random_mac_address()
|
data['mac'] = _get_random_mac_address()
|
||||||
return HttpResponse(json.dumps(data))
|
return HttpResponse(json.dumps(data))
|
||||||
|
|
||||||
|
@ -1157,9 +1176,9 @@ def guess_clone_name(request):
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def check_instance(request, vname):
|
def check_instance(request, vname):
|
||||||
check_instance = Instance.objects.filter(name=vname)
|
instance = Instance.objects.filter(name=vname)
|
||||||
data = {'vname': vname, 'exists': False}
|
data = {'vname': vname, 'exists': False}
|
||||||
if check_instance:
|
if instance:
|
||||||
data['exists'] = True
|
data['exists'] = True
|
||||||
return HttpResponse(json.dumps(data))
|
return HttpResponse(json.dumps(data))
|
||||||
|
|
||||||
|
|
53
networks/templates/modify_fixed_address.html
Normal file
53
networks/templates/modify_fixed_address.html
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{% load i18n %}
|
||||||
|
{% if request.user.is_superuser %}
|
||||||
|
<a href="#AddFixedNet" type="button" class="btn btn-success pull-right" data-toggle="modal">
|
||||||
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Modal pool -->
|
||||||
|
<div class="modal fade" id="AddFixedNet" tabindex="-1" role="dialog" aria-labelledby="AddFixedNetLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">{% trans "Add Fixed Address" %}</h4>
|
||||||
|
</div>
|
||||||
|
<form method="post" action="" role="form">{% csrf_token %}
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{% trans "Subnet Pool" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="text" readonly class="form-control" name="subnet" value="{{ ipv4_network }}" required pattern="[0-9\/\.]+">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{% trans "Name" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="text" class="form-control" name="name" required pattern="[a-zA-Z0-9_]+">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{% trans "Address" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="text" class="form-control" name="address" required pattern="[0-9\/\.]+">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{% trans "MAC" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input type="text" class="form-control" name="mac" required pattern="[0-9\/\:]+">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
|
||||||
|
<button type="submit" class="btn btn-primary" name="modify_fixed_address">{% trans "Create" %}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div> <!-- /.modal-content -->
|
||||||
|
</div> <!-- /.modal-dialog -->
|
||||||
|
</div> <!-- /.modal -->
|
||||||
|
{% endif %}
|
|
@ -34,6 +34,7 @@
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
{% include 'errors_block.html' %}
|
||||||
|
{% include 'messages_block.html' %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6 col-sm-4">
|
<div class="col-xs-6 col-sm-4">
|
||||||
|
@ -66,9 +67,11 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if state %}
|
{#{% if state %}#}
|
||||||
|
<div class="row">
|
||||||
|
<h3 class="page-header">{% trans "IPv4 Configuration" %}</h3>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3 class="page-header">{% trans "IPv4 configuration" %}</h3>
|
|
||||||
<div class="col-xs-6 col-sm-4">
|
<div class="col-xs-6 col-sm-4">
|
||||||
<p>{% trans "IPv4 Forwarding:" %}</p>
|
<p>{% trans "IPv4 Forwarding:" %}</p>
|
||||||
<p>{% trans "Network:" %}</p>
|
<p>{% trans "Network:" %}</p>
|
||||||
|
@ -102,43 +105,81 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% if ipv4_dhcp_range_start and ipv4_dhcp_range_end %}
|
{% if ipv4_dhcp_range_start and ipv4_dhcp_range_end %}
|
||||||
<p>{{ ipv4_dhcp_range_start }}</p>
|
<form method="post" role="form">{% csrf_token %}
|
||||||
<p>{{ ipv4_dhcp_range_end }}</p>
|
{% if state %}
|
||||||
|
<p>{{ ipv4_dhcp_range_start }}</p>
|
||||||
|
<p>{{ ipv4_dhcp_range_end }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p><input name="range_start" value="{{ ipv4_dhcp_range_start }}"/></p>
|
||||||
|
<p><input name="range_end" value="{{ ipv4_dhcp_range_end }}"/></p>
|
||||||
|
<div class="col-xs-10 col-sm-8">
|
||||||
|
<input type="submit" class="btn btn-primary btn-block" value="Apply"
|
||||||
|
name="modify_dhcp_range"
|
||||||
|
title="Edit DHCP Range" onclick="return confirm('{% trans "Are you sure?" %}')"/>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if fixed_address %}
|
{% ifequal ipv4_forward.0 'nat' %}
|
||||||
|
{% if state %}
|
||||||
|
{% include 'modify_fixed_address.html' %}
|
||||||
|
{% endif %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3 class="page-header">{% trans "Fixed Address" %}</h3>
|
<h3 class="page-header">{% trans "Fixed Address" %}</h3>
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% if fixed_address %}
|
||||||
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="panel-group" id="accordion">
|
<div class="panel-group" id="accordion">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
|
||||||
Show
|
{% trans 'Show' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapseOne" class="panel-collapse collapse">
|
<div id="collapseOne" class="panel-collapse collapse">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="input-append form-inline pull-right" style="">
|
|
||||||
|
<div class="input-append form-inline pull-right">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" id="filter_input">
|
<input type="text" class="form-control" id="filter_input">
|
||||||
</div>
|
</div>
|
||||||
<input type="button" class="btn btn-default" id="filter_button" value="Filter">
|
<input type="button" class="btn btn-default" id="filter_button" value="Filter">
|
||||||
<button type="button" class="btn btn-default" id="filter_clear">Clear</button>
|
<button type="button" class="btn btn-default" id="filter_clear">{% trans 'Clear' %}</button>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="text-align: center">{% trans "Address" %}</th>
|
|
||||||
<th style="text-align: center">{% trans "MAC" %}</th>
|
<th style="text-align: center">{% trans "MAC" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Address" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Name" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Action" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody style="text-align: center">
|
<tbody style="text-align: center">
|
||||||
{% for fix in fixed_address %}
|
{% for fix in fixed_address %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ fix.host }}</td>
|
<form method="post" role="form">{% csrf_token %}
|
||||||
<td>{{ fix.mac }}</td>
|
<td><label class="form-control" disabled="true">{{ fix.mac }}</label></td>
|
||||||
|
<td><input class="form-control" value="{{ fix.ip }}" name="address" /></td>
|
||||||
|
<td><input class="form-control" value="{{ fix.name }}" name="name" /></td>
|
||||||
|
<td>
|
||||||
|
<input hidden name="mac" value="{{ fix.mac }}"/>
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary"
|
||||||
|
name="modify_fixed_address"
|
||||||
|
title="Edit entry" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-save"></i>
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger"
|
||||||
|
name="delete_fixed_address"
|
||||||
|
title="Delete entry" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</form>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -149,7 +190,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{#{% endif %}#}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block script %}
|
{% block script %}
|
||||||
|
@ -175,7 +216,6 @@
|
||||||
$('tbody tr:not(:Contains(\'' + filter_val + '\'))').hide();
|
$('tbody tr:not(:Contains(\'' + filter_val + '\'))').hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// add event button labeled "clear"
|
// add event button labeled "clear"
|
||||||
$('#filter_clear').click(function (event) {
|
$('#filter_clear').click(function (event) {
|
||||||
$('#filter_input').val('');
|
$('#filter_input').val('');
|
||||||
|
|
|
@ -8,6 +8,7 @@ from networks.forms import AddNetPool
|
||||||
from vrtManager.network import wvmNetwork, wvmNetworks
|
from vrtManager.network import wvmNetwork, wvmNetworks
|
||||||
from vrtManager.network import network_size
|
from vrtManager.network import network_size
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -121,6 +122,33 @@ def network(request, compute_id, pool):
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err.message)
|
error_messages.append(lib_err.message)
|
||||||
|
if 'modify_fixed_address' in request.POST:
|
||||||
|
name = request.POST.get('name', '')
|
||||||
|
address = request.POST.get('address', '')
|
||||||
|
mac = request.POST.get('mac', '')
|
||||||
|
try:
|
||||||
|
ret_val = conn.modify_fixed_address(name, address, mac)
|
||||||
|
messages.success(request, "Fixed Address Operation Completed.")
|
||||||
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
except libvirtError as lib_err:
|
||||||
|
error_messages.append(lib_err.message)
|
||||||
|
except ValueError as val_err:
|
||||||
|
error_messages.append(val_err.message)
|
||||||
|
if 'delete_fixed_address' in request.POST:
|
||||||
|
mac = request.POST.get('mac', '')
|
||||||
|
conn.delete_fixed_address(mac)
|
||||||
|
messages.success(request, "Fixed Address is Deleted.")
|
||||||
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
|
if 'modify_dhcp_range' in request.POST:
|
||||||
|
range_start = request.POST.get('range_start', '')
|
||||||
|
range_end = request.POST.get('range_end', '')
|
||||||
|
try:
|
||||||
|
conn.modify_dhcp_range(range_start, range_end)
|
||||||
|
messages.success(request, "DHCP Range is Changed.")
|
||||||
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
except libvirtError as lib_err:
|
||||||
|
error_messages.append(lib_err.message)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
|
@ -133,3 +133,21 @@ p {
|
||||||
display: inline;
|
display: inline;
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multiselect {
|
||||||
|
width:27em;
|
||||||
|
height:10em;
|
||||||
|
border:solid 2px #c0c0c0;
|
||||||
|
overflow:auto;
|
||||||
|
padding: 0 1em;
|
||||||
|
margin: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect label {
|
||||||
|
display:block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect-on {
|
||||||
|
color:#ffffff;
|
||||||
|
background-color:#000099;
|
||||||
|
}
|
1108
vrtManager/IPy.py
1108
vrtManager/IPy.py
File diff suppressed because it is too large
Load diff
|
@ -118,9 +118,13 @@ class wvmCreate(wvmConnect):
|
||||||
vol = self.get_volume_by_path(vol_path)
|
vol = self.get_volume_by_path(vol_path)
|
||||||
return vol.storagePoolLookupByVolume()
|
return vol.storagePoolLookupByVolume()
|
||||||
|
|
||||||
def clone_from_template(self, clone, template, metadata=False, owner=default_owner):
|
def clone_from_template(self, clone, template, storage=None, metadata=False, owner=default_owner):
|
||||||
vol = self.get_volume_by_path(template)
|
vol = self.get_volume_by_path(template)
|
||||||
stg = vol.storagePoolLookupByVolume()
|
if not storage:
|
||||||
|
stg = vol.storagePoolLookupByVolume()
|
||||||
|
else:
|
||||||
|
stg = self.get_storage(storage)
|
||||||
|
|
||||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||||
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||||
if storage_type == 'dir':
|
if storage_type == 'dir':
|
||||||
|
|
|
@ -201,7 +201,6 @@ class wvmInstance(wvmConnect):
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=filterrefs)
|
return util.get_xml_path(self._XMLDesc(0), func=filterrefs)
|
||||||
|
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
description = util.get_xml_path(self._XMLDesc(0), "/domain/description")
|
description = util.get_xml_path(self._XMLDesc(0), "/domain/description")
|
||||||
return description if description else ''
|
return description if description else ''
|
||||||
|
@ -248,13 +247,8 @@ class wvmInstance(wvmConnect):
|
||||||
def get_disk_devices(self):
|
def get_disk_devices(self):
|
||||||
def disks(doc):
|
def disks(doc):
|
||||||
result = []
|
result = []
|
||||||
dev = None
|
dev = volume = storage = src_file = None
|
||||||
volume = None
|
disk_format = used_size = disk_size = disk_cache = None
|
||||||
storage = None
|
|
||||||
src_fl = None
|
|
||||||
disk_format = None
|
|
||||||
used_size = None
|
|
||||||
disk_size = None
|
|
||||||
|
|
||||||
for disk in doc.xpath('/domain/devices/disk'):
|
for disk in doc.xpath('/domain/devices/disk'):
|
||||||
device = disk.xpath('@device')[0]
|
device = disk.xpath('@device')[0]
|
||||||
|
@ -262,13 +256,17 @@ class wvmInstance(wvmConnect):
|
||||||
try:
|
try:
|
||||||
dev = disk.xpath('target/@dev')[0]
|
dev = disk.xpath('target/@dev')[0]
|
||||||
bus = disk.xpath('target/@bus')[0]
|
bus = disk.xpath('target/@bus')[0]
|
||||||
src_fl = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
|
src_file = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
|
||||||
try:
|
try:
|
||||||
disk_format = disk.xpath('driver/@type')[0]
|
disk_format = disk.xpath('driver/@type')[0]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
vol = self.get_volume_by_path(src_fl)
|
disk_cache = disk.xpath('driver/@cache')[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
vol = self.get_volume_by_path(src_file)
|
||||||
volume = vol.name()
|
volume = vol.name()
|
||||||
|
|
||||||
disk_size = vol.info()[1]
|
disk_size = vol.info()[1]
|
||||||
|
@ -276,13 +274,13 @@ class wvmInstance(wvmConnect):
|
||||||
stg = vol.storagePoolLookupByVolume()
|
stg = vol.storagePoolLookupByVolume()
|
||||||
storage = stg.name()
|
storage = stg.name()
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
volume = src_fl
|
volume = src_file
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
result.append(
|
result.append(
|
||||||
{'dev': dev, 'bus': bus, 'image': volume, 'storage': storage, 'path': src_fl,
|
{'dev': dev, 'bus': bus, 'image': volume, 'storage': storage, 'path': src_file,
|
||||||
'format': disk_format, 'size': disk_size, 'used': used_size})
|
'format': disk_format, 'size': disk_size, 'used': used_size, 'cache': disk_cache})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
||||||
|
@ -290,10 +288,8 @@ class wvmInstance(wvmConnect):
|
||||||
def get_media_devices(self):
|
def get_media_devices(self):
|
||||||
def disks(doc):
|
def disks(doc):
|
||||||
result = []
|
result = []
|
||||||
dev = None
|
dev = volume = storage = None
|
||||||
volume = None
|
src_file = None
|
||||||
storage = None
|
|
||||||
src_fl = None
|
|
||||||
for media in doc.xpath('/domain/devices/disk'):
|
for media in doc.xpath('/domain/devices/disk'):
|
||||||
device = media.xpath('@device')[0]
|
device = media.xpath('@device')[0]
|
||||||
if device == 'cdrom':
|
if device == 'cdrom':
|
||||||
|
@ -301,22 +297,137 @@ class wvmInstance(wvmConnect):
|
||||||
dev = media.xpath('target/@dev')[0]
|
dev = media.xpath('target/@dev')[0]
|
||||||
bus = media.xpath('target/@bus')[0]
|
bus = media.xpath('target/@bus')[0]
|
||||||
try:
|
try:
|
||||||
src_fl = media.xpath('source/@file')[0]
|
src_file = media.xpath('source/@file')[0]
|
||||||
vol = self.get_volume_by_path(src_fl)
|
vol = self.get_volume_by_path(src_file)
|
||||||
volume = vol.name()
|
volume = vol.name()
|
||||||
stg = vol.storagePoolLookupByVolume()
|
stg = vol.storagePoolLookupByVolume()
|
||||||
storage = stg.name()
|
storage = stg.name()
|
||||||
except:
|
except:
|
||||||
src_fl = None
|
src_file = None
|
||||||
volume = src_fl
|
volume = src_file
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_fl, 'bus': bus})
|
result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_file, 'bus': bus})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
||||||
|
|
||||||
|
def get_bootmenu(self):
|
||||||
|
menu = util.get_xml_path(self._XMLDesc(0), "/domain/os/bootmenu/@enable")
|
||||||
|
return True if menu == 'yes' else False
|
||||||
|
|
||||||
|
def set_bootmenu(self, flag):
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
os = tree.find('os')
|
||||||
|
menu = os.find("bootmenu")
|
||||||
|
|
||||||
|
if menu == None:
|
||||||
|
bootmenu = ElementTree.fromstring("<bootmenu enable='yes'/>")
|
||||||
|
os.append(bootmenu)
|
||||||
|
menu = os.find("bootmenu")
|
||||||
|
|
||||||
|
if flag == 0: # Disable
|
||||||
|
menu.attrib['enable'] = 'no'
|
||||||
|
elif flag == 1: # Enable
|
||||||
|
menu.attrib['enable'] = 'yes'
|
||||||
|
elif flag == -1: # Remove
|
||||||
|
os.remove(menu)
|
||||||
|
else:
|
||||||
|
raise Exception('Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove')
|
||||||
|
|
||||||
|
xmldom = ElementTree.tostring(tree)
|
||||||
|
self._defineXML(xmldom)
|
||||||
|
|
||||||
|
def get_bootorder(self):
|
||||||
|
boot_order = {}
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
os = tree.find('os')
|
||||||
|
boot = os.findall('boot')
|
||||||
|
|
||||||
|
for idx, b in enumerate(boot):
|
||||||
|
dev = b.get('dev')
|
||||||
|
if dev == 'hd':
|
||||||
|
target = "disk"
|
||||||
|
type = "file"
|
||||||
|
elif dev == 'fd':
|
||||||
|
target = "floppy"
|
||||||
|
type = "file"
|
||||||
|
elif dev == 'cdrom':
|
||||||
|
target = "cdrom"
|
||||||
|
type = "file"
|
||||||
|
elif dev == 'network':
|
||||||
|
target = "network"
|
||||||
|
type = "network"
|
||||||
|
boot_order[idx] = {"type": type, "dev": dev, "target": target}
|
||||||
|
|
||||||
|
devices = tree.find('devices')
|
||||||
|
for dev in devices:
|
||||||
|
dev_target = dev_type = dev_device = dev_alias = None
|
||||||
|
boot_dev = dev.find('boot')
|
||||||
|
if boot_dev != None:
|
||||||
|
idx = boot_dev.get('order')
|
||||||
|
dev_type = dev.get('type')
|
||||||
|
dev_device = dev.get('device')
|
||||||
|
|
||||||
|
if dev_type == 'file':
|
||||||
|
dev_target = dev.find('target').get('dev')
|
||||||
|
|
||||||
|
elif dev_type == 'network':
|
||||||
|
dev_mac = dev.find('mac').get('address')
|
||||||
|
dev_device = "network"
|
||||||
|
dev_target = "nic-{}".format(dev_mac[9:])
|
||||||
|
elif dev_type == 'usb':
|
||||||
|
pass
|
||||||
|
|
||||||
|
boot_order[int(idx)-1] = {"type": dev_type, "dev": dev_device, "target": dev_target}
|
||||||
|
|
||||||
|
return boot_order
|
||||||
|
|
||||||
|
def set_bootorder(self, devorder):
|
||||||
|
if not devorder:
|
||||||
|
return
|
||||||
|
|
||||||
|
def remove_bootorder():
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
os = tree.find('os')
|
||||||
|
boot = os.findall('boot')
|
||||||
|
# Remove old style boot order
|
||||||
|
for b in boot:
|
||||||
|
os.remove(b)
|
||||||
|
# Remove rest of them
|
||||||
|
for dev in tree.find('devices'):
|
||||||
|
boot_dev = dev.find('boot')
|
||||||
|
if boot_dev != None:
|
||||||
|
dev.remove(boot_dev)
|
||||||
|
return tree
|
||||||
|
|
||||||
|
tree = remove_bootorder()
|
||||||
|
|
||||||
|
for idx, dev in devorder.items():
|
||||||
|
order = ElementTree.fromstring("<boot order='{}'/>".format(idx + 1))
|
||||||
|
if dev['type'] == 'disk':
|
||||||
|
devices = tree.findall("./devices/disk[@device='disk']")
|
||||||
|
for d in devices:
|
||||||
|
device = d.find("./target[@dev='{}']".format(dev['dev']))
|
||||||
|
if device != None:
|
||||||
|
d.append(order)
|
||||||
|
elif dev['type'] == 'cdrom':
|
||||||
|
devices = tree.findall("./devices/disk[@device='cdrom']")
|
||||||
|
for d in devices:
|
||||||
|
device = d.find("./target[@dev='{}']".format(dev['dev']))
|
||||||
|
if device != None:
|
||||||
|
d.append(order)
|
||||||
|
elif dev['type'] == 'network':
|
||||||
|
devices = tree.findall("./devices/interface[@type='network']")
|
||||||
|
for d in devices:
|
||||||
|
device = d.find("mac[@address='{}']".format(dev['dev']))
|
||||||
|
if device != None:
|
||||||
|
d.append(order)
|
||||||
|
else:
|
||||||
|
raise Exception('Invalid Device Type for boot order')
|
||||||
|
self._defineXML(ElementTree.tostring(tree))
|
||||||
|
|
||||||
def mount_iso(self, dev, image):
|
def mount_iso(self, dev, image):
|
||||||
def attach_iso(dev, disk, vol):
|
def attach_iso(dev, disk, vol):
|
||||||
if disk.get('device') == 'cdrom':
|
if disk.get('device') == 'cdrom':
|
||||||
|
@ -490,11 +601,9 @@ class wvmInstance(wvmConnect):
|
||||||
return telnet_port
|
return telnet_port
|
||||||
|
|
||||||
def get_console_listen_addr(self):
|
def get_console_listen_addr(self):
|
||||||
listen_addr = util.get_xml_path(self._XMLDesc(0),
|
listen_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@listen")
|
||||||
"/domain/devices/graphics/@listen")
|
|
||||||
if listen_addr is None:
|
if listen_addr is None:
|
||||||
listen_addr = util.get_xml_path(self._XMLDesc(0),
|
listen_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/listen/@address")
|
||||||
"/domain/devices/graphics/listen/@address")
|
|
||||||
if listen_addr is None:
|
if listen_addr is None:
|
||||||
return "127.0.0.1"
|
return "127.0.0.1"
|
||||||
return listen_addr
|
return listen_addr
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
from vrtManager.IPy import IP
|
from vrtManager.IPy import IP
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
from libvirt import VIR_NETWORK_SECTION_IP_DHCP_HOST, VIR_NETWORK_SECTION_IP_DHCP_RANGE
|
||||||
|
from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_UPDATE_COMMAND_MODIFY
|
||||||
|
from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG
|
||||||
|
|
||||||
|
|
||||||
def network_size(net, dhcp=None):
|
def network_size(net, dhcp=None):
|
||||||
|
@ -106,6 +110,9 @@ class wvmNetwork(wvmConnect):
|
||||||
def delete(self):
|
def delete(self):
|
||||||
self.net.undefine()
|
self.net.undefine()
|
||||||
|
|
||||||
|
def update(self, command, section, parentIndex, xml, flags=0):
|
||||||
|
return self.net.update(command, section, parentIndex, xml, flags)
|
||||||
|
|
||||||
def get_ipv4_network(self):
|
def get_ipv4_network(self):
|
||||||
xml = self._XMLDesc(0)
|
xml = self._XMLDesc(0)
|
||||||
if util.get_xml_path(xml, "/network/ip") is None:
|
if util.get_xml_path(xml, "/network/ip") is None:
|
||||||
|
@ -169,9 +176,57 @@ class wvmNetwork(wvmConnect):
|
||||||
def network(doc):
|
def network(doc):
|
||||||
result = []
|
result = []
|
||||||
for net in doc.xpath('/network/ip/dhcp/host'):
|
for net in doc.xpath('/network/ip/dhcp/host'):
|
||||||
host = net.xpath('@ip')[0]
|
ip = net.xpath('@ip')[0]
|
||||||
mac = net.xpath('@mac')[0]
|
mac = net.xpath('@mac')[0]
|
||||||
result.append({'host': host, 'mac': mac})
|
name = net.xpath('@name')[0]
|
||||||
|
result.append({'ip': ip, 'mac': mac, 'name': name})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=network)
|
return util.get_xml_path(self._XMLDesc(0), func=network)
|
||||||
|
|
||||||
|
def modify_fixed_address(self, name, address, mac):
|
||||||
|
util.validate_macaddr(mac)
|
||||||
|
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(mac, name, IP(address))
|
||||||
|
new_host_xml = ElementTree.fromstring(new_xml)
|
||||||
|
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
hosts = tree.findall("./ip/dhcp/host")
|
||||||
|
|
||||||
|
host = None
|
||||||
|
for h in hosts:
|
||||||
|
if h.get('mac') == mac:
|
||||||
|
host = h
|
||||||
|
break
|
||||||
|
if host is None:
|
||||||
|
self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE|VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||||
|
else:
|
||||||
|
# change the host
|
||||||
|
if host.get('name') == new_host_xml.get('name') and host.get('ip') == new_host_xml.get('ip'):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE|VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||||
|
|
||||||
|
def delete_fixed_address(self, mac):
|
||||||
|
util.validate_macaddr(mac)
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
hosts = tree.findall("./ip/dhcp/host")
|
||||||
|
|
||||||
|
for h in hosts:
|
||||||
|
if h.get('mac') == mac:
|
||||||
|
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(mac, h.get('name'), h.get('ip'))
|
||||||
|
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE|VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||||
|
break
|
||||||
|
|
||||||
|
def modify_dhcp_range(self, range_start, range_end):
|
||||||
|
if not self.is_active():
|
||||||
|
new_range = '<range start="{}" end="{}"/>'.format(range_start, range_end)
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
dhcp = tree.find("./ip/dhcp")
|
||||||
|
old_range = dhcp.find('range')
|
||||||
|
dhcp.remove(old_range)
|
||||||
|
dhcp.append(ElementTree.fromstring(new_range))
|
||||||
|
|
||||||
|
self.wvm.networkDefineXML(ElementTree.tostring(tree))
|
||||||
|
|
|
@ -153,3 +153,15 @@ def validate_uuid(val):
|
||||||
val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] +
|
val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] +
|
||||||
"-" + val[16:20] + "-" + val[20:32])
|
"-" + val[16:20] + "-" + val[20:32])
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def validate_macaddr(val):
|
||||||
|
if val is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not (isinstance(val, str) or isinstance(val, basestring)):
|
||||||
|
raise ValueError("MAC address must be a string.")
|
||||||
|
|
||||||
|
form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val)
|
||||||
|
if form is None:
|
||||||
|
raise ValueError("MAC address must be of the format AA:BB:CC:DD:EE:FF, was '%s'" % val)
|
||||||
|
|
Loading…
Reference in a new issue