mirror of
				https://github.com/retspen/webvirtcloud
				synced 2025-07-31 12:41:08 +00:00 
			
		
		
		
	
						commit
						d5fe941b2f
					
				
					 12 changed files with 470 additions and 114 deletions
				
			
		|  | @ -36,15 +36,17 @@ | |||
|                         </div> | ||||
|                         <div class="panel-body"> | ||||
|                             <div class="row"> | ||||
|                                 <div class="col-xs-4 col-sm-4"> | ||||
|                                 <div class="col-xs-3"> | ||||
|                                     <p><strong>{% trans "Status" %}:</strong></p> | ||||
|                                 </div> | ||||
|                                 <div class="col-xs-4 col-sm-6"> | ||||
|                                 <div class="col-xs-9"> | ||||
|                                     {% ifequal compute.status 1 %} | ||||
|                                         <p>{% trans "Connected" %}</p> | ||||
|                                     {% else %} | ||||
|                                         <p>{% trans "Not Connected" %}</p> | ||||
|                                     {% endifequal %} | ||||
|                                 </div> | ||||
|                                 <div class="col-xs-offset-3 col-sm-8"> | ||||
|                                     {% if compute.details %} | ||||
|                                         <p>{% trans compute.details %}</p> | ||||
|                                     {% else %} | ||||
|  |  | |||
|  | @ -94,7 +94,7 @@ | |||
| 
 | ||||
|             <div class="noVNC_scroll"> | ||||
| 
 | ||||
|             <h1 class="noVNC_logo" translate="no"><span>no</span><br />VNC</h1> | ||||
|             <h1 class="noVNC_logo" translate="no"><span>no</span><br/>VNC</h1> | ||||
| 
 | ||||
|             <!-- Drag/Pan the viewport --> | ||||
|             <input type="image" alt="viewport drag" src="{% static "js/novnc/app/images/drag.svg" %}" | ||||
|  | @ -225,7 +225,7 @@ | |||
|                                 <div class="noVNC_expander">WebSocket</div> | ||||
|                                 <div><ul> | ||||
|                                     <li> | ||||
|                                         <label><input id="noVNC_setting_encrypt" type="checkbox" /> Encrypt</label> | ||||
|                                         <label><input id="noVNC_setting_encrypt" type="checkbox"/>Encrypt</label> | ||||
|                                     </li> | ||||
|                                      <li> | ||||
|                                         <label for="noVNC_setting_host">Host:</label> | ||||
|  | @ -233,17 +233,17 @@ | |||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <label for="noVNC_setting_port">Port:</label> | ||||
|                                         <input id="noVNC_setting_port" value="{{ ws_port }}" type="number" /> | ||||
|                                         <input id="noVNC_setting_port" value="{{ ws_port }}" type="number"/> | ||||
|                                     </li> | ||||
|                                     <li> | ||||
|                                         <label for="noVNC_setting_path">Path:</label> | ||||
|                                         <input id="noVNC_setting_path" type="input" value="websockify" /> | ||||
|                                         <input id="noVNC_setting_path" type="input" value="websockify"/> | ||||
|                                     </li> | ||||
|                                 </ul></div> | ||||
|                             </li> | ||||
|                             <li><hr></li> | ||||
|                             <li> | ||||
|                                 <label><input id="noVNC_setting_reconnect" type="checkbox" /> Automatic Reconnect</label> | ||||
|                                 <label><input id="noVNC_setting_reconnect" type="checkbox" />Automatic Reconnect</label> | ||||
|                                 <input id="noVNC_setting_autoconnect" type="checkbox" value="true" hidden/> | ||||
|                             </li> | ||||
|                             <li> | ||||
|  | @ -252,7 +252,7 @@ | |||
|                             </li> | ||||
|                             <li><hr></li> | ||||
|                              <li> | ||||
|                                 <label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label> | ||||
|                                 <label><input id="noVNC_setting_show_dot" type="checkbox">Show Dot when No Cursor</label> | ||||
|                             </li> | ||||
|                             <li><hr></li> | ||||
|                             <!-- Logging selection dropdown --> | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_BUS | |||
| from webvirtcloud.settings import INSTANCE_CPU_DEFAULT_MODE | ||||
| from webvirtcloud.settings import INSTANCE_MACHINE_DEFAULT_TYPE | ||||
| from webvirtcloud.settings import QEMU_CONSOLE_DEFAULT_TYPE | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_IO | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DISCARD | ||||
| from django.contrib import messages | ||||
| from logs.views import addlogmsg | ||||
| 
 | ||||
|  | @ -97,7 +100,10 @@ def create_instance(request, compute_id, arch, machine): | |||
|         instances = conn.get_instances() | ||||
|         videos = conn.get_video_models(arch, machine) | ||||
|         cache_modes = sorted(conn.get_cache_modes().items()) | ||||
|         default_cache = INSTANCE_VOLUME_DEFAULT_CACHE | ||||
|         default_cache = INSTANCE_VOLUME_DEFAULT_CACHE.lower() | ||||
|         default_io = INSTANCE_VOLUME_DEFAULT_IO.lower() | ||||
|         default_zeroes = INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES.lower() | ||||
|         default_discard = INSTANCE_VOLUME_DEFAULT_DISCARD.lower() | ||||
|         listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES | ||||
|         mac_auto = util.randomMAC() | ||||
|         disk_devices = conn.get_disk_device_types(arch, machine) | ||||
|  | @ -238,6 +244,7 @@ def create_instance(request, compute_id, arch, machine): | |||
|                                                      vcpu_mode=data['vcpu_mode'], uuid=uuid, arch=arch, machine=machine, | ||||
|                                                      firmware=firmware, | ||||
|                                                      images=volume_list, cache_mode=data['cache_mode'], | ||||
|                                                      io_mode=default_io, discard_mode=default_discard, detect_zeroes_mode=default_zeroes, | ||||
|                                                      networks=data['networks'], virtio=data['virtio'], | ||||
|                                                      listen_addr=data["listener_addr"], nwfilter=data["nwfilter"], | ||||
|                                                      graphics=data["graphics"], video=data["video"], | ||||
|  |  | |||
|  | @ -84,7 +84,8 @@ | |||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="modal-footer"> | ||||
|                                     <button type="submit" class="btn btn-lg btn-success pull-right" name="add_new_vol">{% trans "Add Volume" %}</button> | ||||
|                                     <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button> | ||||
|                                     <button type="submit" class="btn btn-success" name="add_new_vol">{% trans "Add Volume" %}</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                             </div> | ||||
|  | @ -138,7 +139,8 @@ | |||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="modal-footer"> | ||||
|                                      <button type="submit" class="btn btn-lg btn-success pull-right" name="add_existing_vol">{% trans "Add Volume" %}</button> | ||||
|                                      <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button> | ||||
|                                      <button type="submit" class="btn btn-success" name="add_existing_vol">{% trans "Add Volume" %}</button> | ||||
|                                 </div> | ||||
|                             </form> | ||||
|                             </div> | ||||
|  |  | |||
							
								
								
									
										126
									
								
								instances/templates/edit_instance_volume.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								instances/templates/edit_instance_volume.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | |||
| {% load i18n %} | ||||
| {% if request.user.is_superuser %} | ||||
|     <button href="#editvol{{ id }}" type="button" class="btn btn-sm btn-default" data-toggle="modal" title="Edit Volume"> | ||||
|         <i class="glyphicon glyphicon-edit" aria-hidden="true"></i> | ||||
|     </button> | ||||
| 
 | ||||
|     <!-- Modal pool --> | ||||
|     <div class="modal fade" id="editvol{{ id }}" tabindex="-1" role="dialog" aria-labelledby="editInstanceVolumeLabel{{ id }}" 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 "Edit Instance Volume" %}</h4> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="modal-body"> | ||||
| 
 | ||||
|                         <ul class="nav nav-tabs"> | ||||
|                             <li role="presentation" class="active"><a href="#VirtualDisk{{ id }}" data-toggle="tab">{% trans 'Virtual Disk' %}</a></li> | ||||
|                             <li role="presentation"><a href="#PerformanceVolume{{ id }}" data-toggle="tab">{% trans 'Performance' %}</a></li> | ||||
|                             <li role="presentation"><a href="#AdvancedVolume{{ id }}" data-toggle="tab">{% trans 'Advanced' %}</a></li> | ||||
|                         </ul> | ||||
| 
 | ||||
|                         <div class="tab-content"> | ||||
| 
 | ||||
|                             <div class="tab-pane active" id="VirtualDisk{{ id }}"> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Volume Path' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <input class="form-control" name="vol_path" value="{{ disk.path }}"/> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Readonly' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <input class="form-control-static" type="checkbox" name="vol_readonly" value="True" {% if disk.readonly %}checked{% endif %}/> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Shareable' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <input class="form-control-static" type="checkbox" name="vol_shareable" value="True" {% if disk.shareable %}checked{% endif %}/> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
| 
 | ||||
|                             <div class="tab-pane" id="AdvancedVolume{{ id }}"> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Bus' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <select class="form-control" name="vol_bus"> | ||||
|                                         {% for bus in bus_host %} | ||||
|                                             <option value="{{ bus }}" {% if bus == disk.bus %}selected{% endif %}>{{ bus }}</option> | ||||
|                                         {% endfor %} | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Serial Number' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <input class="form-control" type="text" name="vol_serial" value="{{ disk.serial }}"/> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Storage Format' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <input class="form-control" type="text" name="vol_format" value="{{ disk.format }}"/> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
| 
 | ||||
|                             <div class="tab-pane" id="PerformanceVolume{{ id }}"> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Cache mode' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <select class="form-control" name="vol_cache"> | ||||
|                                         {% for key, val in cache_modes %} | ||||
|                                             <option value="{{ key }}" {% if key == disk.cache %}selected{% endif %}>{{ val }}</option> | ||||
|                                         {% endfor %} | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'IO mode' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <select class="form-control" name="vol_io_mode"> | ||||
|                                         {% for key, val in io_modes %} | ||||
|                                             <option value="{{ key }}" {% if key == disk.io %}selected{% endif %}>{{ val }}</option> | ||||
|                                         {% endfor %} | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Discard mode' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <select class="form-control" name="vol_discard_mode"> | ||||
|                                         {% for key, val in discard_modes %} | ||||
|                                             <option value="{{ key }}" {% if key == disk.discard %}selected{% endif %}>{{ val }}</option> | ||||
|                                         {% endfor %} | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="form-group"> | ||||
|                                     <label class="col-sm-4 control-label">{% trans 'Detect zeroes' %}</label> | ||||
|                                     <div class="col-sm-8"> | ||||
|                                         <select class="form-control" name="vol_detect_zeroes"> | ||||
|                                         {% for key, val in detect_zeroes_modes %} | ||||
|                                             <option value="{{ key }}" {% if key == disk.detect_zeroes %}selected{% endif %}>{{ val }}</option> | ||||
|                                         {% endfor %} | ||||
|                                         </select> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div><!-- /.tabpane-content --> | ||||
|                         </div><!-- /.tab-content --> | ||||
|                 </div> <!-- /.modal-body --> | ||||
|                 <div class="clearfix"></div> | ||||
|                 <div class="modal-footer"> | ||||
|                     <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button> | ||||
|                     <button type="submit" class="btn btn-success" name="edit_volume">{% trans "Save" %}</button> | ||||
|                 </div><!-- /.modal-footer --> | ||||
| 
 | ||||
|             </div> <!-- /.modal-content --> | ||||
|         </div> <!-- /.modal-dialog --> | ||||
| 
 | ||||
|     </div> <!-- /.modal --> | ||||
| {% endif %} | ||||
|  | @ -34,6 +34,11 @@ | |||
|                 {% for disk in disks %} | ||||
|                     {{ disk.size|filesizeformat }} {% trans "Disk" %} | | ||||
|                 {% endfor %} | ||||
|                 {% for net in networks %} | ||||
|                    {% for ipv4 in net.ipv4|default:"-" %} | ||||
|                        {{ ipv4 }} | | ||||
|                    {% endfor %} | ||||
|                 {% endfor %} | ||||
|                 <button | ||||
|                     {% if guest_agent == True %} | ||||
|                         {% if guest_agent_ready == True %} | ||||
|  | @ -823,14 +828,14 @@ | |||
|                                                 <th>{% trans "Capacity" %}</th> | ||||
|                                                 <th>{% trans "Storage" %}</th> | ||||
|                                                 <th>{% trans "Source" %}</th> | ||||
|                                                 <th style="width:100px;">{% trans "Action" %}</th> | ||||
|                                                 <th>{% trans "Action" %}</th> | ||||
|                                             </thead> | ||||
|                                             <tbody> | ||||
|                                             {% for disk in disks %} | ||||
|                                                 <tr> | ||||
|                                                     <td> | ||||
|                                                         <button type="submit" class="btn btn-sm btn-default" | ||||
|                                                                 name="details" | ||||
|                                                                 name="details{{ forloop.counter0 }}" | ||||
|                                                                 title="{% trans "Details" %}" | ||||
|                                                                 tabindex="0" | ||||
|                                                                 data-trigger="focus" | ||||
|  | @ -838,7 +843,13 @@ | |||
|                                                                 data-html="true" | ||||
|                                                                 data-content="<strong>Bus:</strong> {{ disk.bus }} <br/> | ||||
|                                                                               <strong>Format:</strong> {{ disk.format }} <br/> | ||||
|                                                                               <strong>Cache:</strong> {{ disk.cache }}"> | ||||
|                                                                               <strong>Cache:</strong> {{ disk.cache }} <br/> | ||||
|                                                                               <strong>Serial:</strong> {{ disk.serial }} <br/> | ||||
|                                                                               <strong>Readonly:</strong> {{ disk.readonly }} <br/> | ||||
|                                                                               <strong>Shareable:</strong> {{ disk.shareable }}</br> | ||||
|                                                                               <strong>IO Mode:</strong> {{ disk.io }} <br/> | ||||
|                                                                               <strong>Discard:</strong> {{ disk.discard }} <br/> | ||||
|                                                                               <strong>Detect Zeroes:</strong> {{ disk.detect_zeroes }}"> | ||||
|                                                             <i class="fa fa-info"></i> | ||||
|                                                         </button> | ||||
|                                                         {{ disk.dev }} | ||||
|  | @ -850,11 +861,12 @@ | |||
|                                                     <td>{{ disk.storage }}</td> | ||||
|                                                     <td>{{ disk.path }}</td> | ||||
|                                                     <td> | ||||
|                                                         <form action="" method="post" style="height:10px" role="form">{% csrf_token %} | ||||
|                                                         <form action="" method="post" role="form">{% csrf_token %} | ||||
|                                                             <input type="hidden" name="path" value="{{ disk.path }}"> | ||||
|                                                             <input type="hidden" name="dev" value="{{ disk.dev }}"> | ||||
|                                                             <input type="hidden" name="storage" value="{{ disk.storage }}"> | ||||
|                                                             <input type="hidden" name="name" value="{{ disk.image }}"> | ||||
|                                                             {% include 'edit_instance_volume.html' with id=forloop.counter0 %} | ||||
|                                                             {% ifequal status 5 %} | ||||
|                                                                 <button type="submit" class="btn btn-sm btn-default" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume?" %}')"> | ||||
|                                                                     <i class="fa fa-eject"></i> | ||||
|  | @ -863,14 +875,15 @@ | |||
|                                                                     <i class="fa fa-trash"></i> | ||||
|                                                                 </button> | ||||
|                                                             {% else %} | ||||
|                                                                 <button class="btn btn-sm btn-default disabled" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume after shutdown?" %}')"> | ||||
|                                                                 <button class="btn btn-sm btn-default disabled" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')"> | ||||
|                                                                     <i class="fa fa-eject"></i> | ||||
|                                                                 </button> | ||||
|                                                                 <button class="btn btn-sm btn-default disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure to delete after shutdown?" %}')"> | ||||
|                                                                 <button class="btn btn-sm btn-default disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')"> | ||||
|                                                                     <i class="fa fa-trash"></i> | ||||
|                                                                 </button> | ||||
|                                                             {% endifequal %} | ||||
|                                                         </form> | ||||
| 
 | ||||
|                                                     </td> | ||||
|                                                 </tr> | ||||
|                                             {% endfor %} | ||||
|  | @ -887,44 +900,35 @@ | |||
| 
 | ||||
|                             <div class="col-xs-12 col-sm-12"> | ||||
|                                 <p><strong>{% trans "Network Devices" %}</strong></p> | ||||
|                                 <table class="table table-hover"> | ||||
|                                 <table class="table table-condensed table-responsive"> | ||||
|                                     <thead> | ||||
|                                     <tr> | ||||
|                                         <th>{% trans 'Name' %}</th> | ||||
|                                         <th>{% trans 'MAC' %}</th> | ||||
|                                         <th>{% trans 'IP Address' %}</th> | ||||
|                                         <th>{% trans 'Source' %}</th> | ||||
|                                         <th>{% trans 'LinkState' %}</th> | ||||
|                                         <th>{% trans 'Filter' %}</th> | ||||
|                                         <th>{% trans 'Qos' %}</th> | ||||
|                                         <th>{% trans 'Actions' %}</th> | ||||
|                                         <th class="hidden-xs hidden-sm" colspan="6">{% trans 'Info' %}</th> | ||||
|                                         <th class="visible-xs visible-sm" colspan="2">{% trans 'Info' %}</th> | ||||
|                                         <th colspan="2">{% trans 'Actions' %}</th> | ||||
|                                     </tr> | ||||
|                                     </thead> | ||||
|                                     <tbody> | ||||
|                                         {% for network in networks %} | ||||
|                                     {% for network in networks %} | ||||
|                                         <tr> | ||||
|                                             <td class="col-sm-1">eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</td> | ||||
|                                             <td>{{ network.mac }}</td> | ||||
|                                             <td>{{ network.ipv4|default:"unknown" }}</td> | ||||
|                                             <td>{{ network.nic }}</td> | ||||
|                                             <td> | ||||
|                                             <form method="post">{% csrf_token %} | ||||
|                                                 <input name="mac" value="{{ network.mac }}" hidden/> | ||||
|                                                 <input name="set_link_state" value="{{ network.state }}" hidden/> | ||||
|                                                 <input type="checkbox" {% if network.state == 'up' %} checked | ||||
|                                                 {% endif %} onclick='submit();' /> | ||||
|                                                 {% trans 'active' %} | ||||
|                                             </form> | ||||
|                                             </td> | ||||
|                                             <td>{{ network.filterref|default:"None" }}</td> | ||||
|                                             <td> | ||||
|                                                 <form class="form-horizontal" method="post" name="add_qos{{ forloop.counter0 }}" role="form">{% csrf_token %} | ||||
|                                                     <input type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}" hidden/> | ||||
|                                                     {% include 'add_network_qos.html' with id=forloop.counter0 %} | ||||
|                                             <td rowspan="2">eth{{ forloop.counter0 }}({{ network.target|default:"no target" }}) | ||||
|                                                 <form method="post">{% csrf_token %} | ||||
|                                                     <input name="mac" value="{{ network.mac }}" hidden/> | ||||
|                                                     <input name="set_link_state" value="{{ network.state }}" hidden/> | ||||
|                                                     <input type="checkbox" {% if network.state == 'up' %} checked | ||||
|                                                     {% endif %} onclick='submit();' /> | ||||
|                                                     <strong>{% trans 'active' %}</strong> | ||||
|                                                 </form> | ||||
|                                             </td> | ||||
|                                             <td class="col-sm-2"> | ||||
|                                             <form class="form-horizontal" method="post" name="set_qos{{ forloop.counter0 }}" role="form">{% csrf_token %} | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'MAC' %}</th> | ||||
|                                             <td>{{ network.mac }}</td> | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'Filter' %}</th> | ||||
|                                             <td class="hidden-xs">{{ network.filterref|default:"None" }}</td> | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'Source' %}</th> | ||||
|                                             <td>{{ network.nic }}</td> | ||||
|                                             <td> | ||||
|                                             <form class="form-horizontal" method="post" name="edit_network{{ forloop.counter0 }}" role="form">{% csrf_token %} | ||||
|                                                 <button data-target="#editInstanceNetwork{{ forloop.counter0 }}" type="button" class="btn btn-sm btn-primary" | ||||
|                                                         title="Edit NIC" data-toggle="modal"> | ||||
|                                                     <span class="glyphicon glyphicon-edit" aria-hidden="true"></span> | ||||
|  | @ -939,13 +943,13 @@ | |||
|                                                             </div> | ||||
|                                                             <div class="modal-body"> | ||||
|                                                                 <div class="form-group form-inline"> | ||||
|                                                                     <label class="col-sm-2 control-label">{% trans "MAC" %} </label> | ||||
|                                                                     <label class="col-sm-3 control-label">{% trans "MAC Addr" %} </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 control-label">{% trans "NIC" %} </label> | ||||
|                                                                     <label class="col-sm-3 control-label">{% trans "Net Source" %} </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 }}"> | ||||
|  | @ -958,7 +962,7 @@ | |||
|                                                                     </select> | ||||
|                                                                 </div> | ||||
|                                                                 <div class="form-group form-inline"> | ||||
|                                                                     <label class="col-sm-2 control-label">{% trans "Filter" %} </label> | ||||
|                                                                     <label class="col-sm-3 control-label">{% trans "NW 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 }}"> | ||||
|  | @ -968,20 +972,59 @@ | |||
|                                                                         {% endfor %} | ||||
|                                                                     </select> | ||||
|                                                                 </div> | ||||
|                                                                 <button class="btn btn-sm btn-primary btn-block" name="change_network" title="{% trans "Apply Network Changes" %}">{% trans "Apply" %}</button> | ||||
|                                                                 <div class="form-group form-inline"> | ||||
|                                                                     <label class="col-sm-3 control-label">{% trans "Model" %} </label> | ||||
|                                                                     <input class="form-control" type="text" value="{{ network.model }}" readonly/> | ||||
|                                                                     <label class="control-label"><em>to</em></label> | ||||
|                                                                     <select class="form-control" name="net-model-{{ forloop.counter0 }}"> | ||||
|                                                                         {% for model in net_models_host %} | ||||
|                                                                         <option value="{{ model }}" {% ifequal model network.model  %} selected {% endifequal %}>{{ model }}</option> | ||||
|                                                                         {% endfor %} | ||||
|                                                                     </select> | ||||
|                                                                 </div> | ||||
|                                                             </div> | ||||
|                                                             <div class="modal-footer"> | ||||
|                                                                 <button class="btn btn-default"  data-dismiss="modal">{% trans 'Close' %}</button> | ||||
|                                                                 <button class="btn btn-success" name="change_network" title="{% trans "Apply Network Changes" %}">{% trans "Apply" %}</button> | ||||
|                                                             </div> | ||||
|                                                         </div> | ||||
|                                                     </div> | ||||
|                                                 </div> | ||||
| 
 | ||||
|                                                 <button class="btn btn-sm btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete Device" %}" | ||||
|                                                     onclick="return confirm('{% trans "Are you sure?" %}')"> | ||||
|                                                     <i class="glyphicon glyphicon-trash"></i> | ||||
|                                                 </button> | ||||
|                                             </form> | ||||
|                                             </td> | ||||
|                                             <td align="right"> | ||||
|                                                 <form method="post" name="delete_network" role="form">{% csrf_token %} | ||||
|                                                     <button class="btn btn-sm btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete Device" %}" | ||||
|                                                         onclick="return confirm('{% trans "Are you sure?" %}')"> | ||||
|                                                         <i class="glyphicon glyphicon-trash"></i> | ||||
|                                                     </button> | ||||
|                                                 </form> | ||||
|                                             </td> | ||||
|                                         </tr> | ||||
|                                         {% endfor %} | ||||
|                                         <tr> | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'IPv4' %}</th> | ||||
|                                             <td> | ||||
|                                                 {% for ipv4 in network.ipv4|default:"unknown" %}{{ ipv4 }}{% endfor %} | ||||
|                                             </td> | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'IPv6' %}</th> | ||||
|                                             <td class="hidden-xs"> | ||||
|                                                 {% for ipv6 in network.ipv6|default:"unknown" %}{{ ipv6 }}{% endfor %} | ||||
|                                             </td> | ||||
|                                             <th class="hidden-xs hidden-sm">{% trans 'Model' %}</th> | ||||
|                                             <td>{{ network.model }}</td> | ||||
|                                             <th>{% trans 'QoS' %}</th> | ||||
|                                             <td align="right"> | ||||
|                                                 <form class="form-horizontal" method="post" name="add_qos{{ forloop.counter0 }}" role="form">{% csrf_token %} | ||||
|                                                     <input type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}" hidden/> | ||||
|                                                     {% include 'add_network_qos.html' with id=forloop.counter0 %} | ||||
|                                                 </form> | ||||
|                                             </td> | ||||
|                                         </tr> | ||||
|                                         <tr> | ||||
|                                             <td class="bg-primary hidden-xs hidden-sm" colspan="9"></td> | ||||
|                                             <td class="bg-primary visible-xs visible-sm" colspan="5"></td> | ||||
|                                         </tr> | ||||
|                                     {% endfor %} | ||||
|                                     </tbody> | ||||
|                                 </table> | ||||
|                             </div> | ||||
|  | @ -994,7 +1037,7 @@ | |||
|                                 <table class="table table-hover"> | ||||
|                                     <thead> | ||||
|                                     <tr> | ||||
|                                         <th>{% trans "Direction" %}</th> | ||||
|                                         <th>{% trans "MAC/Direction" %}</th> | ||||
|                                         <th>{% trans "Average" %}</th> | ||||
|                                         <th>{% trans "Peak" %}</th> | ||||
|                                         <th>{% trans "Burst" %}</th> | ||||
|  |  | |||
|  | @ -313,6 +313,12 @@ def instance(request, compute_id, vname): | |||
|         clone_free_names = get_clone_free_names() | ||||
|         user_quota_msg = check_user_quota(0, 0, 0, 0) | ||||
|         cache_modes = sorted(conn.get_cache_modes().items()) | ||||
|         io_modes = sorted(conn.get_io_modes().items()) | ||||
|         discard_modes = sorted(conn.get_discard_modes().items()) | ||||
|         detect_zeroes_modes = sorted(conn.get_detect_zeroes_modes().items()) | ||||
|         default_io = settings.INSTANCE_VOLUME_DEFAULT_IO | ||||
|         default_discard = settings.INSTANCE_VOLUME_DEFAULT_DISCARD | ||||
|         default_zeroes = settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES | ||||
|         default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE | ||||
|         default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT | ||||
|         default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER | ||||
|  | @ -347,6 +353,7 @@ def instance(request, compute_id, vname): | |||
|         networks_host = sorted(conn.get_networks()) | ||||
|         nwfilters_host = conn.get_nwfilters() | ||||
|         storages_host = sorted(conn.get_storages(True)) | ||||
|         net_models_host = conn.get_network_models() | ||||
| 
 | ||||
|         try: | ||||
|             interfaces_host = sorted(conn.get_ifaces()) | ||||
|  | @ -506,6 +513,7 @@ def instance(request, compute_id, vname): | |||
|                     conn.resize_cpu(cur_vcpu, vcpu) | ||||
|                     msg = _("Resize CPU") | ||||
|                     addlogmsg(request.user.username, instance.name, msg) | ||||
|                     messages.success(request, msg) | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#resize') | ||||
| 
 | ||||
|             if 'resizevm_mem' in request.POST and (request.user.is_superuser or | ||||
|  | @ -529,6 +537,7 @@ def instance(request, compute_id, vname): | |||
|                     conn.resize_mem(cur_memory, memory) | ||||
|                     msg = _("Resize Memory") | ||||
|                     addlogmsg(request.user.username, instance.name, msg) | ||||
|                     messages.success(request, msg) | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#resize') | ||||
| 
 | ||||
|             if 'resizevm_disk' in request.POST and ( | ||||
|  | @ -549,6 +558,7 @@ def instance(request, compute_id, vname): | |||
|                     conn.resize_disk(disks_new) | ||||
|                     msg = _("Resize") | ||||
|                     addlogmsg(request.user.username, instance.name, msg) | ||||
|                     messages.success(request, msg) | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#resize') | ||||
| 
 | ||||
|             if 'add_new_vol' in request.POST and allow_admin_or_not_template: | ||||
|  | @ -563,10 +573,10 @@ def instance(request, compute_id, vname): | |||
|                 meta_prealloc = True if request.POST.get('meta_prealloc', False) else False | ||||
|                 bus = request.POST.get('bus', default_bus) | ||||
|                 cache = request.POST.get('cache', default_cache) | ||||
|                 target = get_new_disk_dev(media, disks, bus) | ||||
|                 target_dev = get_new_disk_dev(media, disks, bus) | ||||
| 
 | ||||
|                 path = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_owner) | ||||
|                 conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus) | ||||
|                 source = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_owner) | ||||
|                 conn.attach_disk(source, target_dev, target_bus=bus, driver_type=format, cache_mode=cache) | ||||
|                 msg = _('Attach new disk {} ({})'.format(name, format)) | ||||
|                 addlogmsg(request.user.username, instance.name, msg) | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#disks') | ||||
|  | @ -583,16 +593,43 @@ def instance(request, compute_id, vname): | |||
|                                          compute.type, | ||||
|                                          storage) | ||||
| 
 | ||||
|                 format = conn_create.get_volume_type(name) | ||||
|                 driver_type = conn_create.get_volume_type(name) | ||||
|                 path = conn_create.get_target_path() | ||||
|                 target = get_new_disk_dev(media, disks, bus) | ||||
|                 target_dev = get_new_disk_dev(media, disks, bus) | ||||
|                 source = path + "/" + name | ||||
| 
 | ||||
|                 conn.attach_disk(source, target, subdriver=format, cache=cache, targetbus=bus) | ||||
|                 msg = _('Attach Existing disk: ' + target) | ||||
|                 conn.attach_disk(source, target_dev, target_bus=bus, driver_type=driver_type, cache_mode=cache) | ||||
|                 msg = _('Attach Existing disk: ' + target_dev) | ||||
|                 addlogmsg(request.user.username, instance.name, msg) | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#disks') | ||||
| 
 | ||||
|             if 'edit_volume' in request.POST and allow_admin_or_not_template: | ||||
|                 target_dev = request.POST.get('dev', '') | ||||
| 
 | ||||
|                 new_path = request.POST.get('vol_path', '') | ||||
|                 shareable = bool(request.POST.get('vol_shareable', False)) | ||||
|                 readonly = bool(request.POST.get('vol_readonly', False)) | ||||
|                 bus = request.POST.get('vol_bus', '') | ||||
|                 serial = request.POST.get('vol_serial', '') | ||||
|                 format = request.POST.get('vol_format', '') | ||||
|                 cache = request.POST.get('vol_cache', default_cache) | ||||
|                 io = request.POST.get('vol_io_mode', default_io) | ||||
|                 discard = request.POST.get('vol_discard_mode', default_discard) | ||||
|                 zeroes = request.POST.get('vol_detect_zeroes', default_zeroes) | ||||
| 
 | ||||
|                 conn.edit_disk(target_dev, new_path, readonly, shareable, bus, serial, format, | ||||
|                                cache, io, discard, zeroes) | ||||
| 
 | ||||
|                 if not conn.get_status() == 5: | ||||
|                     messages.success(request, _("Disk changes changes are applied. " + | ||||
|                                                 "But it will be activated after shutdown")) | ||||
|                 else: | ||||
|                     messages.success(request, _("Disk is changed successfully.")) | ||||
|                 msg = _('Edit disk: ' + target_dev) | ||||
|                 addlogmsg(request.user.username, instance.name, msg) | ||||
| 
 | ||||
|                 return HttpResponseRedirect(request.get_full_path() + '#disks') | ||||
| 
 | ||||
|             if 'delete_vol' in request.POST and allow_admin_or_not_template: | ||||
|                 storage = request.POST.get('storage', '') | ||||
|                 conn_delete = wvmStorage(compute.hostname, | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
|     </a> | ||||
| 
 | ||||
|     <!-- Modal pool --> | ||||
|     <div class="modal fade" id="AddQos{{ id }}" tabindex="-1" role="dialog" aria-labelledby="AddQosLabel" | ||||
|     <div class="modal fade" id="AddQos{{ id }}" tabindex="-1" role="dialog" aria-labelledby="AddQosLabel{{ id }}" | ||||
|          aria-hidden="true"> | ||||
|         <div class="modal-dialog"> | ||||
|             <div class="modal-content"> | ||||
|  |  | |||
|  | @ -494,6 +494,31 @@ class wvmConnect(object): | |||
|             'unsafe': 'Unsafe',  # since libvirt 0.9.7 | ||||
|         } | ||||
| 
 | ||||
|     def get_io_modes(self): | ||||
|         """Get io threads available modes""" | ||||
|         return { | ||||
|             'default': 'Default', | ||||
|             'native': 'Native', | ||||
|             'threads': 'Threads', | ||||
|         } | ||||
| 
 | ||||
|     def get_discard_modes(self): | ||||
|         """Get discard available modes""" | ||||
|         return { | ||||
|             'default': 'Default', | ||||
|             'ignore': 'Ignore', | ||||
|             'unmap': 'Unmap', | ||||
|         } | ||||
| 
 | ||||
|     def get_detect_zeroes_modes(self): | ||||
|         """Get detect zeroes available modes""" | ||||
|         return { | ||||
|             'default': 'Default', | ||||
|             'on': 'On', | ||||
|             'off': 'Off', | ||||
|             'unmap': 'Unmap', | ||||
|         } | ||||
| 
 | ||||
|     def get_hypervisors_domain_types(self): | ||||
|         """Return hypervisor type""" | ||||
|         def hypervisors(ctx): | ||||
|  | @ -614,6 +639,10 @@ class wvmConnect(object): | |||
|             return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")] | ||||
|         return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_hostdev_list) | ||||
| 
 | ||||
|     def get_network_models(self): | ||||
|         """Get available image filename extensions""" | ||||
|         return ['default', 'e1000', 'virtio'] | ||||
| 
 | ||||
|     def get_image_formats(self): | ||||
|         """Get available image formats""" | ||||
|         return ['raw', 'qcow', 'qcow2'] | ||||
|  |  | |||
|  | @ -4,7 +4,8 @@ from vrtManager.connection import wvmConnect | |||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as DEFAULT_OWNER | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_FORMAT | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER | ||||
| from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DRIVER_OPTS as OPTS | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -165,7 +166,11 @@ class wvmCreate(wvmConnect): | |||
|         vol = self.get_volume_by_path(path) | ||||
|         vol.delete() | ||||
| 
 | ||||
|     def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, images, cache_mode, networks, nwfilter, graphics, virtio, listen_addr, video="vga", console_pass="random", mac=None, qemu_ga=False): | ||||
|     def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, images, | ||||
|                         networks, nwfilter, graphics, virtio, listen_addr, | ||||
|                         video="vga", console_pass="random", mac=None, | ||||
|                         cache_mode=None, io_mode=None, discard_mode=None, detect_zeroes_mode=None, | ||||
|                         qemu_ga=True): | ||||
|         """ | ||||
|         Create VM function | ||||
|         """ | ||||
|  | @ -173,7 +178,6 @@ class wvmCreate(wvmConnect): | |||
|         dom_caps = self.get_dom_capabilities(arch, machine) | ||||
| 
 | ||||
|         memory = int(memory) * 1024 | ||||
|         #hypervisor_type = 'kvm' if self.is_kvm_supported() else 'qemu' | ||||
| 
 | ||||
|         xml = """ | ||||
|                 <domain type='%s'> | ||||
|  | @ -237,6 +241,17 @@ class wvmCreate(wvmConnect): | |||
|         hd_disk_letters = list(string.lowercase) | ||||
|         sd_disk_letters = list(string.lowercase) | ||||
|         add_cd = True | ||||
| 
 | ||||
|         disk_opts = '' | ||||
|         if cache_mode is not None and cache_mode != 'default': | ||||
|             disk_opts += "cache='%s' " % cache_mode | ||||
|         if io_mode is not None and io_mode != 'default': | ||||
|             disk_opts += "io='%s' " % io_mode | ||||
|         if discard_mode is not None and discard_mode != 'default': | ||||
|             disk_opts += "discard='%s' " % discard_mode | ||||
|         if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': | ||||
|             disk_opts += "detect_zeroes='%s' " % detect_zeroes_mode | ||||
| 
 | ||||
|         for volume in images: | ||||
|             stg = self.get_storage_by_vol_path(volume['path']) | ||||
|             stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") | ||||
|  | @ -246,7 +261,7 @@ class wvmCreate(wvmConnect): | |||
|             if stg_type == 'rbd': | ||||
|                 ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg) | ||||
|                 xml += """<disk type='network' device='disk'> | ||||
|                             <driver name='qemu' type='%s' cache='%s' %s />""" % (volume['type'], cache_mode, OPTS.get("network", '')) | ||||
|                             <driver name='qemu' type='%s' %s />""" % (volume['type'], disk_opts) | ||||
|                 xml += """  <auth username='%s'> | ||||
|                                 <secret type='ceph' uuid='%s'/> | ||||
|                             </auth> | ||||
|  | @ -262,7 +277,7 @@ class wvmCreate(wvmConnect): | |||
|                 xml += """</source>""" | ||||
|             else: | ||||
|                 xml += """<disk type='file' device='%s'>""" % volume['device'] | ||||
|                 xml += """ <driver name='qemu' type='%s' cache='%s' %s/>""" % (volume['type'], cache_mode, OPTS.get("file", '')) | ||||
|                 xml += """ <driver name='qemu' type='%s' %s/>""" % (volume['type'], disk_opts) | ||||
|                 xml += """ <source file='%s'/>""" % volume['path'] | ||||
| 
 | ||||
|             if volume.get('bus') == 'virtio': | ||||
|  | @ -313,7 +328,12 @@ class wvmCreate(wvmConnect): | |||
| 
 | ||||
|         if 'usb' in dom_caps['disk_bus']: | ||||
|             xml += """<input type='mouse' bus='{}'/>""".format('virtio' if virtio else 'usb') | ||||
|             xml += """<input type='keyboard' bus='{}'/>""".format('virtio' if virtio else 'usb') | ||||
|             xml += """<input type='tablet' bus='{}'/>""".format('virtio' if virtio else 'usb') | ||||
|         else: | ||||
|             xml += """<input type='mouse'/>""" | ||||
|             xml += """<input type='keyboard'/>""" | ||||
|             xml += """<input type='tablet'/>""" | ||||
| 
 | ||||
|         xml += """ | ||||
|                 <graphics type='%s' port='-1' autoport='yes' %s listen='%s'/> | ||||
|  |  | |||
|  | @ -287,8 +287,8 @@ class wvmInstance(wvmConnect): | |||
|         leases = [] | ||||
| 
 | ||||
|         def extract_dom(info): | ||||
|             ipv4 = None | ||||
|             ipv6 = None | ||||
|             ipv4 = [] | ||||
|             ipv6 = [] | ||||
|             for addrs in info.values(): | ||||
|                 if addrs["hwaddr"] != iface_mac: | ||||
|                     continue | ||||
|  | @ -296,20 +296,20 @@ class wvmInstance(wvmConnect): | |||
|                     continue | ||||
|                 for addr in addrs["addrs"]: | ||||
|                     if addr["type"] == 0: | ||||
|                         ipv4 = addr["addr"] | ||||
|                         ipv4.append(addr["addr"]) | ||||
|                     elif (addr["type"] == 1 and | ||||
|                           not str(addr["addr"]).startswith("fe80")): | ||||
|                         ipv6 = addr["addr"] + "/" + str(addr["prefix"]) | ||||
|                         ipv6.append(addr["addr"] + "/" + str(addr["prefix"])) | ||||
|             return ipv4, ipv6 | ||||
| 
 | ||||
|         def extract_lease(info): | ||||
|             ipv4 = None | ||||
|             ipv6 = None | ||||
|             ipv4 = [] | ||||
|             ipv6 = [] | ||||
|             if info["mac"] == iface_mac: | ||||
|                 if info["type"] == 0: | ||||
|                     ipv4 = info["ipaddr"] | ||||
|                     ipv4.append(info["ipaddr"]) | ||||
|                 elif info["type"] == 1: | ||||
|                     ipv6 = info["ipaddr"] | ||||
|                     ipv6.append(info["ipaddr"]) | ||||
|             return ipv4, ipv6 | ||||
| 
 | ||||
|         for ips in ([qemuga] + leases + [arp]): | ||||
|  | @ -354,6 +354,7 @@ class wvmInstance(wvmConnect): | |||
|                 target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0] | ||||
|                 link_state = 'up' if not net.xpath('link') else net.xpath('link/@state')[0] | ||||
|                 filterref_inst = '' if not net.xpath('filterref/@filter') else net.xpath('filterref/@filter')[0] | ||||
|                 model_type = net.xpath('model/@type')[0] | ||||
|                 if net.xpath('bandwidth/inbound'): | ||||
|                     in_attr = net.xpath('bandwidth/inbound')[0] | ||||
|                     in_av = in_attr.get('average') | ||||
|  | @ -375,6 +376,7 @@ class wvmInstance(wvmConnect): | |||
|                                'nic': nic_inst, | ||||
|                                'target': target_inst, | ||||
|                                'state': link_state, | ||||
|                                'model': model_type, | ||||
|                                'ipv4': ipv4, | ||||
|                                'ipv6': ipv6, | ||||
|                                'filterref': filterref_inst, | ||||
|  | @ -388,10 +390,13 @@ class wvmInstance(wvmConnect): | |||
|     def get_disk_devices(self): | ||||
|         def disks(doc): | ||||
|             result = [] | ||||
|             dev = volume = storage = src_file = bus = None | ||||
|             disk_format = used_size = disk_size = disk_cache = None | ||||
|              | ||||
|             for disk in doc.xpath('/domain/devices/disk'): | ||||
|                 dev = volume = storage = src_file = bus = None | ||||
|                 disk_format = used_size = disk_size = None | ||||
|                 disk_cache = disk_io = disk_discard = disk_zeroes = 'default' | ||||
|                 readonly = shareable = serial = None | ||||
| 
 | ||||
|                 device = disk.xpath('@device')[0] | ||||
|                 if device == 'disk': | ||||
|                     try: | ||||
|  | @ -406,6 +411,23 @@ class wvmInstance(wvmConnect): | |||
|                             disk_cache = disk.xpath('driver/@cache')[0] | ||||
|                         except: | ||||
|                             pass | ||||
|                         try: | ||||
|                             disk_io = disk.xpath('driver/@io')[0] | ||||
|                         except: | ||||
|                             pass | ||||
|                         try: | ||||
|                             disk_discard = disk.xpath('driver/@discard')[0] | ||||
|                         except: | ||||
|                             pass | ||||
|                         try: | ||||
|                             disk_zeroes = disk.xpath('driver/@detect_zeroes')[0] | ||||
|                         except: | ||||
|                             pass | ||||
| 
 | ||||
|                         readonly = True if disk.xpath('readonly') else False | ||||
|                         shareable = True if disk.xpath('shareable') else False | ||||
|                         serial = disk.xpath('serial')[0].text if disk.xpath('serial') else None | ||||
| 
 | ||||
|                         try: | ||||
|                             vol = self.get_volume_by_path(src_file) | ||||
|                             volume = vol.name() | ||||
|  | @ -421,7 +443,9 @@ class wvmInstance(wvmConnect): | |||
|                     finally: | ||||
|                         result.append( | ||||
|                             {'dev': dev, 'bus': bus, 'image': volume, 'storage': storage, 'path': src_file, | ||||
|                              'format': disk_format, 'size': disk_size, 'used': used_size, 'cache': disk_cache}) | ||||
|                              'format': disk_format, 'size': disk_size, 'used': used_size, | ||||
|                              'cache': disk_cache, 'io': disk_io, 'discard': disk_discard, 'detect_zeroes': disk_zeroes, | ||||
|                              'readonly': readonly, 'shareable': shareable, 'serial': serial}) | ||||
|             return result | ||||
| 
 | ||||
|         return util.get_xml_path(self._XMLDesc(0), func=disks) | ||||
|  | @ -620,39 +644,88 @@ class wvmInstance(wvmConnect): | |||
|             xmldom = ElementTree.tostring(tree) | ||||
|         self._defineXML(xmldom) | ||||
| 
 | ||||
|     def attach_disk(self, source, target, sourcetype='file', device='disk', driver='qemu', subdriver='raw', cache='none', targetbus='ide'): | ||||
|         xml_disk = "<disk type='%s' device='%s'>" % (sourcetype, device) | ||||
|         if device == 'cdrom': | ||||
|             xml_disk += "<driver name='%s' type='%s'/>" % (driver, subdriver) | ||||
|         elif device == 'disk': | ||||
|             xml_disk += "<driver name='%s' type='%s' cache='%s'/>" % (driver, subdriver, cache) | ||||
|     def attach_disk(self, source, target_dev, target_bus='ide', disk_type='file', | ||||
|                     disk_device='disk', driver_name='qemu', driver_type='raw', | ||||
|                     readonly=False, shareable=False, serial=None, | ||||
|                     cache_mode=None, io_mode=None, discard_mode=None, detect_zeroes_mode=None): | ||||
| 
 | ||||
|         additionals = '' | ||||
|         if cache_mode is not None and cache_mode != 'default': | ||||
|             additionals += "cache='%s' " % cache_mode | ||||
|         if io_mode is not None and io_mode != 'default': | ||||
|             additionals += "io='%s' " % io_mode | ||||
|         if discard_mode is not None and discard_mode != 'default': | ||||
|             additionals += "discard='%s' " % discard_mode | ||||
|         if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': | ||||
|             additionals += "detect_zeroes='%s' " % detect_zeroes_mode | ||||
| 
 | ||||
|         xml_disk = "<disk type='%s' device='%s'>" % (disk_type, disk_device) | ||||
|         if disk_device == 'cdrom': | ||||
|             xml_disk += "<driver name='%s' type='%s'/>" % (driver_name, driver_type) | ||||
|         elif disk_device == 'disk': | ||||
|             xml_disk += "<driver name='%s' type='%s' %s/>" % (driver_name, driver_type, additionals) | ||||
|         xml_disk += """<source file='%s'/> | ||||
|           <target dev='%s' bus='%s'/> | ||||
|         </disk> | ||||
|         """ % (source, target, targetbus) | ||||
|           <target dev='%s' bus='%s'/>""" % (source, target_dev, target_bus) | ||||
|         if readonly: | ||||
|             xml_disk += """<readonly/>""" | ||||
|         if shareable: | ||||
|             xml_disk += """<shareable/>""" | ||||
|         if serial is not None and serial != 'None' and serial != '': | ||||
|             xml_disk += """<serial>%s</serial>""" % serial | ||||
|         xml_disk += """</disk>""" | ||||
|         if self.get_status() == 1: | ||||
|             self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_LIVE) | ||||
|             self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) | ||||
|         if self.get_status() == 5: | ||||
|             self.instance.attachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) | ||||
| 
 | ||||
|     def detach_disk(self, dev): | ||||
|         tree = ElementTree.fromstring(self._XMLDesc(0)) | ||||
|     def detach_disk(self, target_dev): | ||||
|         tree = etree.fromstring(self._XMLDesc(0)) | ||||
| 
 | ||||
|         for disk in tree.findall("./devices/disk"): | ||||
|             target = disk.find("target") | ||||
|             if target.get("dev") == dev: | ||||
|                 devices = tree.find('devices') | ||||
|                 devices.remove(disk) | ||||
|         disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent() | ||||
|         xml_disk = etree.tostring(disk_el) | ||||
|         devices = tree.find('devices') | ||||
|         devices.remove(disk_el) | ||||
| 
 | ||||
|                 if self.get_status() == 1: | ||||
|                     xml_disk = ElementTree.tostring(disk) | ||||
|                     ret = self.instance.detachDevice(xml_disk) | ||||
|                     xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE) | ||||
|                 if self.get_status() == 5: | ||||
|                     xmldom = ElementTree.tostring(tree) | ||||
|                 break | ||||
|         self._defineXML(xmldom) | ||||
|         if self.get_status() == 1: | ||||
|             self.instance.detachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_LIVE) | ||||
|             self.instance.detachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) | ||||
|         if self.get_status() == 5: | ||||
|             self.instance.detachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) | ||||
| 
 | ||||
|     def edit_disk(self, target_dev, source, readonly, shareable, target_bus, serial, format, cache_mode, io_mode, discard_mode, detect_zeroes_mode): | ||||
|         tree = etree.fromstring(self._XMLDesc(0)) | ||||
|         disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent() | ||||
|         old_disk_type = disk_el.get('type') | ||||
|         old_disk_device = disk_el.get('device') | ||||
|         old_driver_name = disk_el.xpath('driver/@name')[0] | ||||
| 
 | ||||
|         additionals = '' | ||||
|         if cache_mode is not None and cache_mode != 'default': | ||||
|             additionals += "cache='%s' " % cache_mode | ||||
|         if io_mode is not None and io_mode != 'default': | ||||
|             additionals += "io='%s' " % io_mode | ||||
|         if discard_mode is not None and discard_mode != 'default': | ||||
|             additionals += "discard='%s' " % discard_mode | ||||
|         if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': | ||||
|             additionals += "detect_zeroes='%s' " % detect_zeroes_mode | ||||
| 
 | ||||
|         xml_disk = "<disk type='%s' device='%s'>" % (old_disk_type, old_disk_device) | ||||
|         if old_disk_device == 'cdrom': | ||||
|             xml_disk += "<driver name='%s' type='%s'/>" % (old_driver_name, format) | ||||
|         elif old_disk_device == 'disk': | ||||
|             xml_disk += "<driver name='%s' type='%s' %s/>" % (old_driver_name, format, additionals) | ||||
|         xml_disk += """<source file='%s'/> | ||||
|           <target dev='%s' bus='%s'/>""" % (source, target_dev, target_bus) | ||||
|         if readonly: | ||||
|             xml_disk += """<readonly/>""" | ||||
|         if shareable: | ||||
|             xml_disk += """<shareable/>""" | ||||
|         if serial is not None and serial != 'None' and serial != '': | ||||
|             xml_disk += """<serial>%s</serial>""" % serial | ||||
|         xml_disk += """</disk>""" | ||||
| 
 | ||||
|         self.instance.updateDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) | ||||
| 
 | ||||
|     def cpu_usage(self): | ||||
|         cpu_usage = {} | ||||
|  | @ -1241,14 +1314,21 @@ class wvmInstance(wvmConnect): | |||
|             net_source = network_data.get('net-source-' + str(num)) | ||||
|             net_source_type = network_data.get('net-source-' + str(num) + '-type') | ||||
|             net_filter = network_data.get('net-nwfilter-' + str(num)) | ||||
|             net_model = network_data.get('net-model-' + str(num)) | ||||
|             bridge_name = self.get_bridge_name(net_source, net_source_type) | ||||
|             if interface.get('type') == 'bridge': | ||||
|                 source = interface.find('mac') | ||||
|                 source.set('address', net_mac) | ||||
|                 source = interface.find('source') | ||||
|                 source.set('bridge', bridge_name) | ||||
|                 source = interface.find('filterref') | ||||
| 
 | ||||
|                 source = interface.find('model') | ||||
|                 if net_model != 'default': | ||||
|                     source.attrib['type'] = net_model | ||||
|                 else: | ||||
|                     interface.remove(source) | ||||
| 
 | ||||
|                 source = interface.find('filterref') | ||||
|                 if net_filter: | ||||
|                     if source is not None: source.set('filter', net_filter) | ||||
|                     else: | ||||
|  | @ -1262,8 +1342,14 @@ class wvmInstance(wvmConnect): | |||
|                 source.set('address', net_mac) | ||||
|                 source = interface.find('source') | ||||
|                 source.set('network', net_source) | ||||
|                 source = interface.find('filterref') | ||||
| 
 | ||||
|                 source = interface.find('model') | ||||
|                 if net_model != 'default': | ||||
|                     source.attrib['type'] = net_model | ||||
|                 else: | ||||
|                     interface.remove(source) | ||||
| 
 | ||||
|                 source = interface.find('filterref') | ||||
|                 if net_filter: | ||||
|                     if source is not None: source.set('filter', net_filter) | ||||
|                     else: | ||||
|  |  | |||
|  | @ -158,17 +158,21 @@ INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2' | |||
| # available bus types: virtio, scsi, ide, usb, sata | ||||
| INSTANCE_VOLUME_DEFAULT_BUS = 'virtio' | ||||
| 
 | ||||
| #SCSI types: 'virtio-scsi', 'lsilogic' | ||||
| #SCSI types: virtio-scsi, lsilogic | ||||
| INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER = 'virtio-scsi' | ||||
| 
 | ||||
| # Volume optionals: two variable: disk driver type is file and network(rbd, iscsi), | ||||
| # optionals : discard='unmap|ignore', detect_zeroes='on|off|unmap', copy_on_read='on|off' | ||||
| # Example: {"file": "discard='unmap' copy_on_read='on'", "network": "detect_zeroes='unmap'"} | ||||
| INSTANCE_VOLUME_DEFAULT_DRIVER_OPTS = {"file": "", "network": ""} | ||||
| 
 | ||||
| # available cache types: none, unsafe, writeback, writethrough | ||||
| # Volume cache: default, directsync, none, unsafe, writeback, writethrough | ||||
| INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync' | ||||
| 
 | ||||
| # Volume io mode: default, native, threads | ||||
| INSTANCE_VOLUME_DEFAULT_IO = 'default' | ||||
| 
 | ||||
| # Volume detect zeroes mode: default, on, off, unmap | ||||
| INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES = 'default' | ||||
| 
 | ||||
| # Volume discard mode: default, unmap, ignore | ||||
| INSTANCE_VOLUME_DEFAULT_DISCARD = 'default' | ||||
| 
 | ||||
| # up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu) | ||||
| INSTANCE_VOLUME_DEFAULT_OWNER = {'uid': 0, 'guid': 0} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue