1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/instances/templates/create_instance_w2.html
catborise 03ac93ea53 fix(instances): CD-ROM bus, USB controller and MACs of a new VM
Creating each option on a RHEL qemu-kvm host showed:

- CD-ROM: the create page offered every disk bus, but the empty CD-ROM
  of a new VM works only on ide, sata and scsi. fdc and virtio failed
  ("Invalid bus type", "does not support ejectable media"), usb failed
  with a device named 'Nonea' because vol_dev_type() had no prefix for
  usb, and after that libvirt refuses an empty usb disk. Only ide, sata
  and scsi are offered now, and another value is refused before any
  storage is allocated. vol_dev_type() names usb disks sdX, which also
  fixes data volumes on the usb bus.
- USB controller: any input device added a bare <controller
  type='usb'/>, which libvirt turns into piix3-uhci (USB 1.1) on q35
  instead of its default qemu-xhci. The bare controller is gone; libvirt
  adds the machine's default for USB inputs.
- MACs: with more networks than MAC addresses, create_instance indexed
  past the list and the request failed with a 500. NICs without a given
  MAC now get one from libvirt. MAC addresses are validated (format, not
  more than networks) by the page and the API before anything is
  created; they went into the XML unchecked.

Unit tests cover the refused values, the MAC rule and the usb prefix.
Live tests create a VM with every offered CD-ROM bus and start it,
check the USB controller with a USB input device and create a VM with
two networks and one MAC.
2026-10-04 18:33:28 +03:00

967 lines
64 KiB
HTML

{% extends "base.html" %}
{% load i18n %}
{% load static %}
{% load bootstrap_icons %}
{% block title %}{% trans "Create new instance" %}{% endblock %}
{% block style %}
<link href="{% static "css/bootstrap-multiselect.css" %}" rel="stylesheet">
{% endblock %}
{% block page_heading %}
{% blocktrans with host=compute.name %}New instance on {{ host }} {% endblocktrans %}
{% endblock page_heading %}
{% block content %}
{% include 'pleasewaitdialog.html' %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ field.label }}:</strong> <span>{{ error|escape }}</span>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<div class="row">
<div class="col-lg-12">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance create method">
<li class="nav-item" role="presentation">
<button class="nav-link float-end" data-bs-toggle="tab" data-bs-target="#" type="button" role="tab" aria-controls="go_compute" onclick="goto_compute()">
<span>{% bs_icon 'arrow-left'%} </span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#flavor" type="button" role="tab" aria-controls="flavor" aria-selected="true">
{% trans "Flavor" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#addCustom" type="button" role="tab" aria-controls="addCustom" aria-selected="false">
{% trans "Custom" %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#add-from-temp" type="button" role="tab" aria-controls="add-from-temp" aria-selected="false">
{% trans "Template" %}
</button>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="flavor">
{% include 'create_flav_block.html' %}
<h3 class="page-header">{% trans "Create from flavor" %}</h3>
{% if not flavors %}
<div class="col-lg-12">
<div class="alert alert-warning shadow-sm">
{% bs_icon 'exclamation-triangle'%} <strong>{% trans "Warning" %}:</strong> {% trans "Hypervisor doesn't have any Flavors" %}
</div>
</div>
{% else %}
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">{% trans "Name" %}</th>
<th scope="col">{% trans "VCPU" %}</th>
<th scope="col">{% trans "RAM" %}</th>
<th scope="col">{% trans "HDD" %}</th>
<th scope="colgroup" colspan="2">{% trans "Action" %}</th>
</tr>
</thead>
<tbody>
{% for flavor in flavors %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ flavor.label }}</td>
<td>{{ flavor.vcpu }}</td>
<td>{{ flavor.memory }} {% trans "MB" %}</td>
<td>{{ flavor.disk }} {% trans "GB" %}</td>
<td style="width:5px;">
<div class="modal fade" id="addVMflavor{{ forloop.counter }}" tabindex="-1" role="dialog" aria-labelledby="addVMFlavorLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Create Virtual Machine" %} ({{ flavor.label }})</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="post" role="form" aria-label="Create instance from flavor form">{% csrf_token %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Name" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="name"
placeholder="{% trans "Name" %}" maxlength="64" required
pattern="[a-zA-Z0-9\.\-_]+">
<input type="hidden" name="vcpu" value="{{ flavor.vcpu }}">
<input type="hidden" name="memory" value="{{ flavor.memory }}">
<input type="hidden" name="hdd_size" value="{{ flavor.disk }}">
</div>
</div>
{% if firmwares %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Firmware" %}</label>
<div class="col-sm-7">
<select class="form-select" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm in default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
{% if dom_caps.cpu_modes %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-7">
<select class="form-select" id="vcpu_mode" name="vcpu_mode">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% if mode == default_cpu_mode %}selected {% endif %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Storage" %}</label>
<div class="col-sm-7">
<input type="hidden" name="cache_mode" value="default">
<select class="form-select" name="storage">
{% if storages %}
{% for storage in storages %}
<option value="{{ storage }}">{{ storage }}</option>
{% endfor %}
{% else %}
<option value="">{% trans "None" %}</option>
{% endif %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Network" %}</label>
<div class="col-sm-7">
<select class="form-select" name="networks">
{% for network in networks %}
<option value="{{ network }}">{{ network }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Advanced" %}</label>
<div class="d-grid col-sm-7">
<button class="btn btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#flav-add-collapse" aria-expanded="false" aria-controls="flav-add-collapse">
<span>{% bs_icon 'caret-down'%} </span>
</button>
</div>
</div>
<div class="collapse" id="flav-add-collapse">
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "MAC" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="mac" maxlength="17" value="{{ mac_auto }}" required pattern="[a-zA-Z0-9:]+">
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "NWFilter" %}</label>
<div class="col-sm-7">
<select class="form-select" name="nwfilter">
<option value="">{% trans "None" %}</option>
{% for nwfilter in nwfilters %}
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "NIC Type" %} </label>
<div class="col-sm-7">
<select class="form-select" name="net_model">
{% for model in net_models_host %}
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "HDD cache mode" %}</label>
<div class="col-sm-7">
<select class="form-select" id="cache_mode" name="cache_mode">
{% for mode, name in cache_modes %}
<option value="{{ mode }}" {% if mode == default_cache %}selected {% endif %}>
{% trans name %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">
<select class="form-select" name="video">
{% if not videos %}
<option value="vga">vga</option>
<option value="cirrus">cirrus</option>
{% endif %}
{% for video in videos %}
<option value="{{ video }}" {% if default_video == video %}selected{% endif %}>{{ video }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Console Access" %}</label>
<div class="col-sm-7">
<select class="form-select" name="listener_addr">
{% for addr, label in listener_addr %}
<option value="{{ addr }}" {% if addr == "0.0.0.0" %} selected {% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Console Password" %}</label>
<div class="col-sm-7">
<input class="form-control" type="password" name="console_pass" placeholder="{% trans "Console Password" %}" maxlength="64">
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Add CD-Rom" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_cdrom" name="add_cdrom">
<option value="None" {% if bus == default_cdrom %}selected{% endif %}>--{% trans "False" %}--</option>
{% for bus in cdrom_buses %}
<option value="{{ bus }}" {% if bus == default_cdrom %}selected {% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Add Input Device" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_input" name="add_input">
<option value="None" {% if bus == default_input_device_bus %}selected{% endif %}>--{% trans "False" %}--</option>
{% for bus in input_device_buses %}
<option value="{{ bus }}" {% if bus == default_input_device_bus %}selected{% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "Guest Agent" %}</label>
<div class="col-sm-7">
<input type="checkbox" name="qemu_ga" value="true" checked>
</div>
</div>
{% if virtio_support %}
<div class="row">
<label class="col-sm-4 col-form-label">{% trans "VirtIO" %}</label>
<div class="col-sm-7">
<input type="checkbox" name="virtio" value="{{ virtio_support }}" checked>
</div>
</div>
{% endif %}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
{% if storages %}
<button type="submit" class="btn btn-primary" name="create">{% trans "Create" %}</button>
{% else %}
<button class="btn btn-primary disabled">{% trans "Create" %}</button>
{% endif %}
</div>
</form>
</div>
</div>
</div>
<a data-bs-toggle="modal" href="#addVMflavor{{ forloop.counter }}" class="btn btn-sm btn-secondary">
<span >{% bs_icon 'plus'%} </span>
</a>
</td>
<td style="width:5px;">
<form action="{% url 'instances:flavor_delete' flavor.id %}" method="post" role="form" aria-label="Delete flavor form">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-secondary" name="delete_flavor" onclick="return confirm('{% trans "Are you sure?" %}')">
{% bs_icon 'trash' %}
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addCustom">
<div>
<form method="post" role="form" aria-label="Create custom instance form">{% csrf_token %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+">
</div>
</div>
{% if firmwares %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Firmware" %}</label>
<div class="col-sm-7">
<select class="form-select" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm == default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VCPU" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]">
</div>
</div>
{% if dom_caps.cpu_modes %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-7">
<select class="form-select" id="vcpu_mode" name="vcpu_mode">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% if mode == default_cpu_mode %}selected {% endif %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "RAM" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="memory" value="512" maxlength="5" required pattern="[0-9]+">
</div>
<label class="col-sm-1 col-form-label">{% trans "MB" %}</label>
</div>
<div id="disk_list_div" class="row d-none">
<label class="col-sm-3 col-form-label" id="added_disks">{% trans "Added Disks" %}</label>
<div class="col-sm-7">
<ul id="img-list" class="row">
<!-- populated from javascript -->
</ul>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "HDD" %}</label>
<input id="images" name="images" type="hidden" value=""/>
<div class="col-sm-3">
<select class="form-select" id="storage-control" name="storage-control" onchange="get_cust_vols({{ compute_id }}, value);">
{% if storages %}
<option value disabled selected>{% trans "Select pool" %}...</option>
{% for storage in storages %}
<option value="{{ storage }}" >{{ storage }}</option>
{% endfor %}
{% else %}
<option value="">{% trans "None" %}</option>
{% endif %}
</select>
</div>
<div class="col-sm-4">
<select class="form-select" id="image-control" name="image-control" multiple="multiple">
<!-- populated from javascript -->
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Network" %}</label>
<div class="col-sm-7">
<ul id="net-list">
<!-- populated from javascript -->
</ul>
<input id="networks" type="hidden" name="networks" value=""/>
<select class="form-select" id="network-control" name="network-control" multiple="multiple">
{% for network in networks %}
<option value="{{ network }}">{{ network }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Advanced" %}</label>
<div class="d-grid col-sm-7">
<button class="btn btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#custadvcollapse" aria-expanded="false" aria-controls="custadvcollapse">
<span>{% bs_icon 'caret-down'%} </span>
</button>
</div>
</div>
<div class="collapse" id="custadvcollapse">
<div class="row meta-prealloc">
<label class="col-sm-3 col-form-label">{% trans "Disk Metadata" %}</label>
<div class="col-sm-7">
<input type="checkbox" name="meta_prealloc" title="{% trans "Metadata preallocation" %}" value="true">
</div>
<label class="col-lg-1 col-form-label">{% trans "Image" %}</label>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "HDD Cache Mode" %}</label>
<div class="col-sm-7">
<select class="form-select" id="cache_mode" name="cache_mode">
{% for mode, name in cache_modes %}
<option value="{{ mode }}" {% if mode == default_cache %}selected {% endif %}>
{% trans name %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "NWFilter" %}</label>
<div class="col-sm-7">
<select class="form-select" name="nwfilter">
<option value="">{% trans "None" %}</option>
{% for nwfilter in nwfilters %}
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "NIC Type" %} </label>
<div class="col-sm-7">
<select class="form-select" name="net_model">
{% for model in net_models_host %}
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">
<select class="form-select" name="video">
{% if not videos %}
<option value="vga">vga</option>
<option value="cirrus">cirrus</option>
{% endif %}
{% for video in videos %}
<option value="{{ video }}">{{ video }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Console Access" %}</label>
<div class="col-sm-7">
<select class="form-select" name="listener_addr">
{% for addr, label in listener_addr %}
<option value="{{ addr }}" {% if addr == "0.0.0.0" %} selected {% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Console Password" %}</label>
<div class="col-sm-7">
<input type="password" class="form-control" name="console_pass" placeholder="{% trans "Console Password" %}" maxlength="64">
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Add CD-Rom" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_cdrom" name="add_cdrom">
<option value="None" {% if bus == default_cdrom %}selected{% endif %} >--{% trans "False" %}--</option>
{% for bus in cdrom_buses %}
<option value="{{ bus }}" {% if bus == default_cdrom %}selected {% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Add Input Device" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_input" name="add_input">
<option value="None" {% if bus == default_input_device_bus %}selected{% endif %}>--{% trans "False" %}--</option>
{% for bus in input_device_buses %}
<option value="{{ bus }}" {% if bus == default_input_device_bus %}selected{% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Guest Agent" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="qemu_ga" value="true" checked>
</div>
</div>
{% if virtio_support %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VirtIO" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="virtio" value="{{ virtio_support }}" checked>
</div>
</div>
{% endif %}
</div>
<div class="row">
<div class="d-grid col-sm-7 offset-3">
{% if storages %}
<button type="submit" class="btn btn-primary" name="create" formnovalidate onclick="showPleaseWaitDialog()" value="1">
{% trans "Create" %}
</button>
{% else %}
<button class="btn btn-primary disabled">
{% trans "Create" %}
</button>
{% endif %}
</div>
</div>
</form>
</div>
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="add-from-temp">
<div>
<form method="post" role="form" aria-label="Create instance from template form">{% csrf_token %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+">
</div>
</div>
{% if firmwares %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Firmware" %}</label>
<div class="col-sm-7">
<select class="form-select" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm == default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VCPU" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]">
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-7">
<select class="form-select" id="vcpu_mode" name="vcpu_mode">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% if mode == default_cpu_mode %}selected{% endif %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "RAM" %}</label>
<div class="col-sm-7">
<input type="text" class="form-control" name="memory" value="512" maxlength="5" required pattern="[0-9]+">
</div>
<label class="col-sm-1 col-form-label">{% trans "MB" %}</label>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Template Disk" %}</label>
<input id="images" name="images" type="hidden" value=""/>
<div class="col-sm-3">
<select class="form-select" onchange="get_template_vols({{ compute_id }}, value);">
{% if storages %}
<option value disabled selected>{% trans "Select pool" %}...</option>
{% for storage in storages %}
<option value="{{ storage }}" >{{ storage }}</option>
{% endfor %}
{% else %}
<option value="">{% trans "None" %}</option>
{% endif %}
</select>
</div>
<div class="col-sm-4">
<select class="form-select" id="template" name="template" disabled>
<!-- populated from javascript -->
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Storage" %}</label>
<div class="col-sm-7">
<select class="form-select" id="storage" name="storage" 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="row">
<label class="col-sm-3 col-form-label">{% trans "Network/MAC" %}</label>
<div class="col-sm-3">
<select class="form-select" name="networks">
{% for network in networks %}
<option value="{{ network }}">{{ network }}</option>
{% endfor %}
</select>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" name="mac" maxlength="17" value="{{ mac_auto }}" required pattern="[a-zA-Z0-9:]+">
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Advanced" %}</label>
<div class="d-grid col-sm-7">
<button class="btn btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#tempAdvCollapse" aria-expanded="false" aria-controls="tempAdvCollapse">
<span>{% bs_icon 'caret-down'%} </span>
</button>
</div>
</div>
<div class="collapse" id="tempAdvCollapse">
<div class="row meta-prealloc">
<label class="col-sm-3 col-form-label">{% trans "Disk Metadata" %}</label>
<div class="col-sm-7">
<input type="checkbox" name="meta_prealloc" title="{% trans "Metadata preallocation" %}" value="true">
</div>
<label class="col-lg-1 col-form-label">{% trans "Image" %}</label>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "HDD cache mode" %}</label>
<div class="col-sm-7">
<select class="form-select" id="cache_mode" name="cache_mode">
{% for mode, name in cache_modes %}
<option value="{{ mode }}" {% if mode == default_cache %}selected{% endif %}>
{% trans name %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "NWFilter" %}</label>
<div class="col-sm-7">
<select class="form-select" name="nwfilter">
<option value="">{% trans "None" %}</option>
{% for nwfilter in nwfilters %}
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "NIC Type" %} </label>
<div class="col-sm-7">
<select class="form-select" name="net_model">
{% for model in net_models_host %}
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Video" %}</label>
<div class="col-sm-7">
<select class="form-select" name="video">
{% if not videos %}
<option value="vga">vga</option>
<option value="cirrus">cirrus</option>
{% endif %}
{% for video in videos %}
<option value="{{ video }}">{{ video }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Console Access" %}</label>
<div class="col-sm-7">
<select class="form-select" name="listener_addr">
{% for addr, label in listener_addr %}
<option value="{{ addr }}" {% if addr == "0.0.0.0" %} selected {% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Console Password" %}</label>
<div class="col-sm-7">
<input type="password" class="form-control" name="console_pass" placeholder="{% trans "Console Password" %}" maxlength="64">
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Add CD-Rom" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_cdrom" name="add_cdrom">
<option value="None" {% if bus == default_cdrom %}selected{% endif %}>--{% trans "False" %}--</option>
{% for bus in cdrom_buses %}
<option value="{{ bus }}" {% if bus == default_cdrom %}selected {% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Add Input Device" %}</label>
<div class="col-sm-7">
<select class="form-select" id="add_input" name="add_input">
<option value="None" {% if bus == default_input_device_bus %}selected{% endif %}>--{% trans "False" %}--</option>
{% for bus in input_device_buses %}
<option value="{{ bus }}" {% if bus == default_input_device_bus %}selected{% endif %}>
{% trans bus %}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "Guest Agent" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="qemu_ga" value="true" checked>
</div>
</div>
{% if virtio_support %}
<div class="row">
<label class="col-sm-3 col-form-label">{% trans "VirtIO" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="virtio" value="{{ virtio_support }}" checked>
</div>
</div>
{% endif %}
</div>
<div class="row">
<div class="d-grid col-sm-7 offset-3">
{% if storages %}
<button type="submit" class="btn btn-primary" name="create" value="1" formnovalidate onclick="showPleaseWaitDialog()">
{% trans "Create" %}
</button>
{% else %}
<button class="btn btn-primary disabled">
{% trans "Create" %}
</button>
{% endif %}
</div>
</div>
</form>
</div>
<div class="clearfix"></div>
</div>
</div><!-- /Tab panes -->
</div>
{% endblock %}
{% block script %}
<script src="{% static 'js/bootstrap-multiselect.js' %}"></script>
<script>
function toggleValue(string, updated_value, checked) {
let result = '';
if (checked) {
result = string;
if (result != '') result += ',';
result += updated_value;
} else {
$.each(string.split(','), function (index, value) {
if (value == updated_value) return;
if (result != '') result += ',';
result += value;
});
}
return result;
}
$(document).ready(function () {
$('#image-control').multiselect({
disableIfEmpty: true,
enableCaseInsensitiveFiltering: true,
maxHeight: 400,
inheritClass: true,
buttonWidth:function (options, select) {
return '100%';
},
buttonText: function (options, select) {
return 'Add image...';
},
buttonTitle: function (options, select) {
return '';
},
onChange: function (element, checked) {
let input_value = toggleValue($('#images').val(), element.val(), checked);
$('#images').val(input_value);
let selected_list_html = '';
let counter = 0;
if (input_value != '') {
$('#disk_list_div').removeClass('d-none');
$.each(input_value.split(','), function (index, value) {
var li = '<li>hdd' + counter + ' - ' +
'<select name="device' + counter + '" class="image-format" onchange="get_disk_bus_choices({{ compute_id }},' + counter + ', value);">' +
'{% for dev in disk_devices %}' +
'<option value=' + '"{{ dev }}">' + '{% trans dev %}</option>' +
'{% endfor %}' +
'</select>' +
'<select id="bus' + counter + '" name="bus' + counter + '" class="image-format">' +
'{% for bus in disk_buses %}' +
'<option value=' + '"{{ bus }}"' +
'{% if bus == default_bus %}selected{% endif %}>' +
'{% trans bus %}</option>' +
'{% endfor %}' +
'</select>' +
' -> ' + value + ' ' +
'<a class="btn-link float-end" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"> X </a></li>';
selected_list_html += li;
counter++;
});
}else {
$('#disk_list_div').addClass('d-none');
}
$('#img-list').html(selected_list_html);
}
});
$('#network-control').multiselect({
inheritClass: true,
buttonText: function (options, select) {
return 'Add network';
},
buttonTitle: function (options, select) {
return '';
},
buttonWidth:function (options, select) {
return '100%';
},
onChange: function (element, checked) {
let input_value = toggleValue($('#networks').val(), element.val(), checked);
$('#networks').val(input_value);
let selected_list_html = '';
mac_array = [];
net_counter = 0;
if (input_value != '') {
$.each(input_value.split(','), function (index, value) {
let li = '<li><input type="text" class="input-xs" name="mac'+ net_counter +'" maxlength="17" required pattern="[a-zA-Z0-9:]+" onchange="populate_mac(' + net_counter +')">' +
' eth' + net_counter +
' -> ' + value + ' ' +
'<a class="btn-link float-end" onclick="$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\', true)"> X </a></li>';
random_mac(net_counter);
selected_list_html += li;
net_counter++;
});
}
$('#net-list').html(selected_list_html);
}
});
});
var mac_array = [];
function random_mac(c) {
$.getJSON("{% url 'instances:random_mac_address' %}", function (data) {
mac_array[c] = data['mac'];
$('input[name="mac' + c + '"').val(data['mac']);
populate_mac(c);
});
}
function populate_mac(c){
mac_array[c] = $('input[name="mac' + c + '"').val();
$('input[name="mac"').val(mac_array.join(","));
}
$("id[vcpu_mode]").multiselect();
function get_cust_vols(compute_id, pool) {
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
$.getJSON(get_vol_url, function (data) {
$("#image-control").find('option').remove();
$.each(data['vols'], function(i, item) {
$("#image-control").append($("<option>").val(item).text(item));
});
$('#image-control').multiselect('rebuild');
});
}
function get_template_vols(compute_id, pool) {
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
$.getJSON(get_vol_url, function (data) {
$("#template").find('option').remove();
$.each(data['vols'], function(i, item) {
$("#template").append($("<option>").val(item).text(item));
});
});
$("#template").removeAttr("disabled");
$("#storage").val(pool).change();
$("#storage").removeAttr("disabled");
}
function get_disk_bus_choices(compute_id, dev_idx, disk_type){
let arch = $('select[name="arch"]').val();
let machine = $("select[id='machine-control']").val();
get_diskBus_url = "/computes/" + compute_id + "/archs/" + arch + "/machines/" + machine + "/disks/" + disk_type + "/buses";
$.getJSON(get_diskBus_url, function (data) {
$("#bus" + dev_idx).find('option').remove();
$.each(data['bus'], function(i, item) {
$("#bus" + dev_idx).append($("<option>").val(item).text(item));
});
});
}
</script>
{% if request.user.is_superuser %}
<script>
function goto_compute() {
let compute = {{ compute.id }};
window.location.href = "{% url 'instances:create_instance_select_type' 1 %}".replace(1, compute);
}
</script>
{% endif %}
{% endblock %}