Merge tag '0.10.2'
[ganeti_webmgr.git] / ganeti_web / templates / ganeti / virtual_machine / detail.html
blob526e3b7e332abc2507ec951dc9201e04edc81890
1 {% extends "menu_base.html" %}
2 {% load webmgr_tags %}
3 {% load i18n %}
4 {% block title %} {% trans "Virtual Machine" %} {{ instance.hostname }}{% endblock %}
5 {% block head %}
6 <link href="{{STATIC_URL}}/css/jquery-ui.css" rel="stylesheet" type="text/css"/>
7 <script src="{{STATIC_URL}}/js/jquery-ui.min.js"></script>
8 <script src="{{STATIC_URL}}/js/jquery.progressbar.js"></script>
9 <script type="text/javascript" src="{{STATIC_URL}}/js/jquery.form.js"></script>
10 <script type="text/javascript" src="{{STATIC_URL}}/js/jquery.ajax.delete.js"></script>
11 <script type="text/javascript">
13 var job_poller;
15 $(document).ready(function() {
16 $('#tabs').tabs({
17 spinner: false,
18 cache: true,
19 select: function(event, ui) {
20 window.location.hash = ui.tab.hash;
22 });
24 {% if admin %}
25 {% ifnotequal instance.info.status "running" %}
26 $('#tabs .ui-tabs-nav a[title=console]').parent()
27 .addClass('ui-state-disabled');
28 {% endifnotequal %}
29 {% endif %}
31 // confirmation dialogs for start, reinstall
32 $("#actions a.power").live("click", function(event) {
33 event.preventDefault();
34 if(!$(this).hasClass('disabled')) {
35 if(!confirm('Are you sure you want to '+ this.title + ' this VM?')) {
36 return false;
38 $.post(this.href, action_response);
40 });
42 // disable buttons that are actually links to other pages
43 $("#actions .edit").live("click", function(event) {
44 return !$(this).hasClass('disabled');
45 });
47 $(".migrate").click(function(event){
48 event.preventDefault();
49 var $this = $(this);
50 if(!$this.hasClass('disabled')) {
51 $('.qtip').qtip('destroy');
53 $(this).qtip({
54 content: {
55 url: this.href,
56 title: {text:"Migrate", button:"close"}
58 position: { corner:{target:'center', tooltip:'center'}},
59 style: {
60 name: 'dark',
61 border:{radius:5},
62 width:400,
63 background:'#eeeeee'},
64 show: {when:false, ready:true},
65 hide: {fixed: true, when:false},
66 api:{onShow:function(){
67 $(".ajax_form input[type!=hidden], .ajax_form select")
68 .first().focus();
70 });
72 });
74 $(".vm_migrate_form").live("submit", function(event){
75 event.preventDefault();
76 $("#errors").empty();
77 $(this).ajaxSubmit({success: vm_form_response});
78 });
80 $(".replace_disks").click(function(event){
81 event.preventDefault();
82 var $this = $(this);
83 if(!$this.hasClass('disabled')) {
84 $('.qtip').qtip('destroy');
86 $(this).qtip({
87 content: {
88 url: this.href,
89 title: {text:"Replace Disks", button:"close"}
91 position: { corner:{target:'center', tooltip:'center'}},
92 style: {
93 name: 'dark',
94 border:{radius:5},
95 width:400,
96 background:'#eeeeee'},
97 show: {when:false, ready:true},
98 hide: {fixed: true, when:false},
99 api:{onShow:function(){
100 $(".ajax_form input[type!=hidden], .ajax_form select")
101 .first().focus();
107 $(".vm_replace_disks_form").live("submit", function(event){
108 event.preventDefault();
109 $("#errors").empty();
110 $(this).ajaxSubmit({success: vm_form_response});
113 job_poller = new JobPoller();
115 var job_status_url = "{% url instance-job-status instance.id %}";
116 var cluster_detail_url = "{% url cluster-detail cluster.slug %}";
117 job_poller.init(job_status_url, cluster_detail_url, job_complete);
118 {% if instance.last_job_id %}
119 job_poller.get_jobs();
120 {% else %}
121 job_poller.poll();
122 {% if instance.error %}
123 display_ganeti_error("{{instance.error}}");
124 {% endif %}
125 {% endif %}
128 function job_complete() {
129 window.location.reload();
132 function action_response(result) {
133 if(result.ops == undefined) {
134 display_ganeti_error(result['__all__'][0]);
135 $('#actions a').removeClass('disabled');
136 } else {
137 job_poller.render_job(result);
138 job_poller.poll(job_poller.FAST);
142 function vm_form_response(responseText, statusText, xhr, $form) {
143 if(responseText["opstatus"] == undefined) {
144 // no opstatus, must be an error
145 // parse errors
146 for (var key in responseText) {
147 $("#errors").append("<li>"+ responseText[key] +"</li>");
149 } else {
150 $('.qtip').qtip("hide");
151 poll_job_status("{% url cluster-detail cluster.slug %}",
152 responseText['id'], job_complete);
153 display_job("{% url cluster-detail cluster.slug %}",
154 responseText);
158 /* XXX: temporarily (maybe permanently) using this for reporting
159 when a quota limit has been encountered on startup */
160 function display_ganeti_error(msg) {
161 $("#messages").empty();
162 var html = "<li class='error'>Error:<p>" + msg + "</p></li>";
163 $("#messages").append(html);
165 </script>
167 <script type="text/javascript" src="{{STATIC_URL}}/js/job_status.js"></script>
169 {% endblock %}
171 {% block content %}
172 <h1 class="breadcrumb">
173 {% if view_cluster %}
174 <a href="{% url cluster-detail cluster.slug %}#virtual_machines">{{cluster.hostname|abbreviate_fqdn}}</a>
175 {% else %}
176 <span>{{cluster.hostname|abbreviate_fqdn}}</span>
177 {% endif %}
178 : {{ instance.hostname }}
179 </h1>
181 <ul id="messages"></ul>
183 <div id="tabs">
184 <ul>
185 <li><a href="#overview">{% trans "Overview" %}</a></li>
186 {% if admin %}
187 <li>
188 <a title="users"
189 href="{% url vm-users cluster.slug instance.hostname %}">
190 {% trans "Users" %}
191 </a>
192 </li>
193 <li>
194 <a title="log"
195 href="{% url vm-object_log cluster.slug instance.hostname %}">
196 {% trans "Log" %}
197 </a>
198 </li>
199 {%endif%}
200 {% if admin or power %}
201 <li>
202 <a title="console"
203 href="{% url instance-vnc cluster.slug instance.hostname %}">
204 {% trans "Console" %}
205 </a>
206 </li>
207 {% endif %}
208 </ul>
209 <div id="overview" class="tab_content">
210 {% if instance.cluster.username %}
211 {% with instance.cluster.username as username %}
212 <ul id="actions">
213 {# Start, Shutdown, Reboot #}
214 {% if admin or power %}
215 {% ifequal instance.info.status "running" %}
216 <li>
217 <a class="button shutdown power" title="shut down" href="{% url instance-shutdown cluster.slug instance.hostname %}">
218 {% trans "Shutdown" %}
219 </a>
220 </li>
221 {% if has_immediate_shutdown %}
222 <li>
223 <a class="button shutdown power"
224 title="Immediate Shutdown"
225 href="{% url instance-shutdown-now cluster.slug instance.hostname %}">
226 {% trans "Immediate Shutdown" %}
227 </a>
228 </li>
229 {% endif %}
230 <li>
231 <a class="button reboot power" title="reboot" href="{% url instance-reboot cluster.slug instance.hostname %}">
232 {% trans "Reboot" %}
233 </a>
234 </li>
235 {% else %}
236 <li>
237 <a class="button startup power" title="start" href="{% url instance-startup cluster.slug instance.hostname %}">
238 {% trans "Start" %}
239 </a>
240 </li>
241 {% endifequal %}
242 {% endif %}
243 {# Reinstall #}
244 {% if remove %}
245 <li>
246 <a class="button reinstall" title="reinstall" href="{% url instance-reinstall cluster.slug instance.hostname %}">
247 {% trans "Reinstall" %}
248 </a>
249 </li>
250 {% endif %}
251 {# Edit #}
252 {% if modify %}
253 <li>
254 <a class="button edit" href="{% url instance-modify cluster.slug instance.hostname %}">
255 {% trans "Edit" %}
256 </a>
257 </li>
258 {% endif %}
259 {# Change Owner #}
260 {% if cluster_admin %}
261 <li>
262 <a class="button edit" href="{% url instance-reparent cluster.slug instance.hostname %}">
263 {% trans "Change Owner" %}
264 </a>
265 </li>
266 {% endif %}
267 {# Rename #}
268 {% if modify %}
269 <li>
270 <a class="button edit" href="{% url instance-rename cluster.slug instance.hostname %}">
271 {% trans "Rename" %}
272 </a>
273 </li>
274 {% endif %}
275 {# Replace Disks and Migrate #}
276 {% if cluster_admin and instance|is_drbd %}
277 {% if replace_disks %}
278 <li>
279 <a class="button replace_disks" title="replace disks" href="{% url instance-replace-disks cluster.slug instance.hostname %}">
280 {% trans "Replace Disks" %}
281 </a>
282 </li>
283 {% endif %}
284 {% endif %}
285 {% if migrate %}
286 {% if instance|is_drbd or instance|is_shared %}
287 <li>
288 <a class="button migrate" title="migrate" href="{% url instance-migrate cluster.slug instance.hostname %}">
289 {% trans "Migrate" %}
290 </a>
291 </li>
292 {% endif %}
293 {% endif %}
294 {# Create Template #}
295 {% if cluster_admin %}
296 <li>
297 <a class="button add" href="{% url template-create-from-instance cluster.slug instance.hostname %}">
298 {% trans "Create Template" %}
299 </a>
300 </li>
301 {% endif %}
302 {# Delete #}
303 {% if remove %}
304 <li>
305 <a class="button delete" title="Delete" href="{% url instance-delete cluster.slug instance.hostname %}">
306 {% trans "Delete" %}
307 </a>
308 </li>
309 {% endif %}
310 </ul>
311 {% endwith %}
312 {% endif %}
314 {% with instance.info as info %}
315 {% if info %}
316 <table class="overview horizontal">
317 <tr><th>{% trans "Owner" %}</th><td>{{ instance.owner.name }}</td></tr>
318 <tr><th>{% trans "Created on" %}</th><td>{{ instance.ctime|date }}</td></tr>
319 <tr><th>{% trans "Last modified" %}</th><td>{{ instance.mtime|date }}</td></tr>
320 <tr>
321 <th>{% trans "Status" %}</th>
322 <td>{{ info.oper_state|yesno:"Running,Stopped" }}</td>
323 </tr>
324 <tr><th>{% trans "Primary node" %}</th><td>
325 {% if cluster_admin %}
326 <a href="{% url node-detail cluster.slug info.pnode %}">
327 {{ info.pnode }}
328 </a>
329 {% else %}
330 {{ info.pnode }}
331 {% endif %}
332 </td></tr>
333 <tr><th>{% trans "Secondary node" %}</th><td>
334 {% if cluster_admin %}
335 {% for host in info.snodes %}
336 <a href="{% url node-detail cluster.slug host %}">
337 {{ host }}
338 </a>
339 {% if not forloop.last %}, {% endif %}
340 {% endfor %}
341 {% else %}
342 {{ info.snodes|join:", " }}
343 {% endif %}
344 </td></tr>
345 <tr>
346 <th>{% trans "Operating System" %}</th>
347 <td>{{ instance.operating_system|render_os }}</td>
348 </tr>
349 <tr>
350 <th>{% trans "Autostart" %}</th>
351 <td>{{ info.admin_state|checkmark }}</td>
352 </tr>
353 <tr>
354 <th>VNC</th>
355 <td>{{ info.pnode }}::{{ info.network_port }}</td>
356 </tr>
357 </table>
359 <h3>Hardware</h3>
360 <table class="horizontal">
361 <tr><th>{% trans "VCPUs" %}</th><td>{{ instance.virtual_cpus }}</td></tr>
362 <tr><th>{% trans "Memory (Min/Max)" %}</th><td>{{ instance.minram|render_storage }} / {{ instance.ram|render_storage }}</td></tr>
363 <tr><th>{% trans "NIC type" %}</th><td>{{ info.hvparams.nic_type }}</td></tr>
364 </table>
366 <h3>{% trans "Disks" %}</h3>
367 <table class="horizontal">
368 <tr><th>{% trans "Disk Template" %}</th><td>{{ info.disk_template }}</td></tr>
369 <tr><th>{% trans "Disk type" %}</th><td>{{ info.hvparams.disk_type }}</td></tr>
370 </table>
371 <table>
372 <tr>
373 <th>{% trans "Disk" %}</th>
374 <th>{% trans "Size" %}</th>
375 </tr>
376 {% for size in info|index:"disk.sizes" %}
377 <tr>
378 <td>disk/{{ forloop.counter0 }}</td>
379 {# <td>{{ info.hvparams.disk_type }}</td> #}
380 <td>{{ size|render_storage }}</td>
381 </tr>
382 {% endfor %}
383 </table>
385 <h3>{% trans "Network Devices" %}</h3>
386 <table>
387 <tr>
388 <th>Nic</th>
389 <th>Mac</th>
390 <th>IP</th>
391 <th>Mode</th>
392 <th>Link</th>
393 </tr>
394 {% for mac in info|index:'nic.macs' %}
395 <tr>
396 <td>nic/{{ forloop.counter0 }}</td>
397 <td>{{ mac }}</td>
398 <td>{{ info|index:'nic.ips'|index:forloop.counter0 }}</td>
399 <td>
400 {{ info|index:'nic.modes'|index:forloop.counter0 }}
401 </td>
402 <td>
403 {{ info|index:'nic.links'|index:forloop.counter0 }}
404 </td>
405 </tr>
406 {% endfor %}
407 </table>
409 <h3>Hypervisor</h3>
410 <table class="horizontal">
411 <tr><th>ACPI</th><td>{{ info.hvparams.acpi|checkmark }}</td></tr>
412 <tr><th>{% trans "Boot Order" %}</th><td>{{ info.hvparams.boot_order }}</td></tr>
413 <tr>
414 <th>{% trans "CDROM Image Path" %}</th>
415 <td>{{ info.hvparams.cdrom_image_path }}</td>
416 </tr>
417 <tr>
418 <th>{% trans "CDROM 2 Image Path" %}</th>
419 <td>{{ info.hvparams.cdrom2_image_path }}</td>
420 </tr>
421 <tr><th>Disk Cache</th><td>{{ info.hvparams.disk_cache }}</td></tr>
422 <tr>
423 <th>initrd Path</th><td>{{ info.hvparams.initrd_path }}</td>
424 </tr>
425 <tr>
426 <th>Kernel Args</th><td>{{ info.hvparams.kernel_args }}</td>
427 </tr>
428 <tr>
429 <th>Kernel Path</th><td>{{ info.hvparams.kernel_path }}</td>
430 </tr>
431 <tr><th>KVM Flag</th><td>{{ info.hvparams.kvm_flag }}</td></tr>
432 <tr><th>Mem Path</th><td>{{ info.hvparams.mem_path }}</td></tr>
433 <tr>
434 <th>Migration Downtime</th>
435 <td>{{ info.hvparams.migration_downtime }}</td>
436 </tr>
437 <tr><th>Nic Type</th><td>{{ info.hvparams.nic_type }}</td></tr>
438 <tr><th>Network Port</th><td>{{ info.network_port }}</td></tr>
439 <tr><th>Root Path</th><td>{{ info.hvparams.root_path }}</td></tr>
440 <tr>
441 <th>Security Domain</th>
442 <td>{{ info.hvparams.security_domain }}</td>
443 </tr>
444 <tr>
445 <th>Security Model</th>
446 <td>{{ info.hvparams.security_model }}</td>
447 </tr>
448 <tr>
449 <th>Serial Console</th>
450 <td>{{ info.hvparams.serial_console|checkmark }}</td>
451 </tr>
452 <tr><th>USB Mouse</th><td>{{ info.hvparams.usb_mouse }}</td></tr>
453 <tr>
454 <th>Use Chroot</th>
455 <td>{{ info.hvparams.use_chroot|checkmark }}</td>
456 </tr>
457 <tr>
458 <th>Use Localtime</th>
459 <td>{{ info.hvparams.use_localtime|checkmark }}</td>
460 </tr>
461 <tr>
462 <th>VNC Bind Address</th>
463 <td>{{ info.hvparams.vnc_bind_address }}</td>
464 </tr>
465 <tr>
466 <th>VNC Password File</th>
467 <td>{{ info.hvparams.vnc_password_file }}</td>
468 </tr>
469 <tr>
470 <th>VNC TLS</th>
471 <td>{{ info.hvparams.vnc_tls|checkmark }}</td>
472 </tr>
473 <tr>
474 <th>VNC x509 Path</th>
475 <td>{{ info.hvparams.vnc_x509_path }}</td>
476 </tr>
477 <tr>
478 <th>VNC x509 Verify</th>
479 <td>{{ info.hvparams.vnc_x509_verify|checkmark }}</td>
480 </tr>
481 </table>
483 {% endif %}
484 {% endwith %}
485 </div>
486 </div>
487 {% endblock %}