[PATCH] Don't fail if no translation can be found
by Cédric Bosdonnat
If a translation file for a locale can't be found, the user gets an
HTTP 50x. Use fallback=True in the translation calls to avoid this and
use the fallback strings instead.
---
ui/pages/error.html.tmpl | 2 +-
ui/pages/guest-add.html.tmpl | 2 +-
ui/pages/guest-edit.html.tmpl | 2 +-
ui/pages/guest-storage-add.html.tmpl | 2 +-
ui/pages/guest.html.tmpl | 2 +-
ui/pages/i18n.json.tmpl | 2 +-
ui/pages/kimchi-ui.html.tmpl | 2 +-
ui/pages/login.html.tmpl | 2 +-
ui/pages/report-add.html.tmpl | 2 +-
ui/pages/report-rename.html.tmpl | 2 +-
ui/pages/repository-add.html.tmpl | 2 +-
ui/pages/repository-edit.html.tmpl | 2 +-
ui/pages/storagepool-add-volume.html.tmpl | 2 +-
ui/pages/storagepool-add.html.tmpl | 2 +-
ui/pages/tabs/guests.html.tmpl | 2 +-
ui/pages/tabs/host.html.tmpl | 2 +-
ui/pages/tabs/network.html.tmpl | 2 +-
ui/pages/tabs/storage.html.tmpl | 2 +-
ui/pages/tabs/templates.html.tmpl | 2 +-
ui/pages/template-add.html.tmpl | 2 +-
ui/pages/template-edit.html.tmpl | 2 +-
21 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/ui/pages/error.html.tmpl b/ui/pages/error.html.tmpl
index 98566c5..d8e16e6 100644
--- a/ui/pages/error.html.tmpl
+++ b/ui/pages/error.html.tmpl
@@ -19,7 +19,7 @@
#encoding UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!doctype html>
diff --git a/ui/pages/guest-add.html.tmpl b/ui/pages/guest-add.html.tmpl
index 3ccafe2..e3270fb 100644
--- a/ui/pages/guest-add.html.tmpl
+++ b/ui/pages/guest-add.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 512909a..62965eb 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -17,7 +17,7 @@
*#
#unicode UTF-8
#import gettext
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
diff --git a/ui/pages/guest-storage-add.html.tmpl b/ui/pages/guest-storage-add.html.tmpl
index c991f42..504316c 100644
--- a/ui/pages/guest-storage-add.html.tmpl
+++ b/ui/pages/guest-storage-add.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<div id="guest-storage-add-window" class="window">
diff --git a/ui/pages/guest.html.tmpl b/ui/pages/guest.html.tmpl
index 74206fd..ebb5e86 100644
--- a/ui/pages/guest.html.tmpl
+++ b/ui/pages/guest.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<li name="guest" class="guest">
diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl
index 959b7be..1edbc19 100644
--- a/ui/pages/i18n.json.tmpl
+++ b/ui/pages/i18n.json.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
{
diff --git a/ui/pages/kimchi-ui.html.tmpl b/ui/pages/kimchi-ui.html.tmpl
index 2f592a6..844234d 100644
--- a/ui/pages/kimchi-ui.html.tmpl
+++ b/ui/pages/kimchi-ui.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
#from kimchi.config import get_version
diff --git a/ui/pages/login.html.tmpl b/ui/pages/login.html.tmpl
index f289af5..e2f6855 100644
--- a/ui/pages/login.html.tmpl
+++ b/ui/pages/login.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
#silent next = "?next=%s" % $getVar('data.next', '') if $getVar('data.next', '') else ""
diff --git a/ui/pages/report-add.html.tmpl b/ui/pages/report-add.html.tmpl
index 2d0c510..e63da44 100644
--- a/ui/pages/report-add.html.tmpl
+++ b/ui/pages/report-add.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/report-rename.html.tmpl b/ui/pages/report-rename.html.tmpl
index 2164af8..5bc91d3 100644
--- a/ui/pages/report-rename.html.tmpl
+++ b/ui/pages/report-rename.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/repository-add.html.tmpl b/ui/pages/repository-add.html.tmpl
index ecd0152..6de4f76 100644
--- a/ui/pages/repository-add.html.tmpl
+++ b/ui/pages/repository-add.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<div id="repository-add-window" class="window">
diff --git a/ui/pages/repository-edit.html.tmpl b/ui/pages/repository-edit.html.tmpl
index 56449f7..f13cb90 100644
--- a/ui/pages/repository-edit.html.tmpl
+++ b/ui/pages/repository-edit.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
diff --git a/ui/pages/storagepool-add-volume.html.tmpl b/ui/pages/storagepool-add-volume.html.tmpl
index 573a764..c0d68f6 100644
--- a/ui/pages/storagepool-add-volume.html.tmpl
+++ b/ui/pages/storagepool-add-volume.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<div id="sp-add-volume-window" class="window">
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 6f1861b..081805b 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -17,7 +17,7 @@
*#
#unicode UTF-8
#import gettext
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/tabs/guests.html.tmpl b/ui/pages/tabs/guests.html.tmpl
index 90d98e5..7bbf570 100644
--- a/ui/pages/tabs/guests.html.tmpl
+++ b/ui/pages/tabs/guests.html.tmpl
@@ -20,7 +20,7 @@
#import gettext
#from Cheetah.Template import Template
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl
index 81266ce..d5a9b1d 100644
--- a/ui/pages/tabs/host.html.tmpl
+++ b/ui/pages/tabs/host.html.tmpl
@@ -19,7 +19,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<div id="host-root-container">
diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl
index 6a6e5f7..6eaa4b3 100644
--- a/ui/pages/tabs/network.html.tmpl
+++ b/ui/pages/tabs/network.html.tmpl
@@ -19,7 +19,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/tabs/storage.html.tmpl b/ui/pages/tabs/storage.html.tmpl
index 523f480..dbbaef9 100644
--- a/ui/pages/tabs/storage.html.tmpl
+++ b/ui/pages/tabs/storage.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/tabs/templates.html.tmpl b/ui/pages/tabs/templates.html.tmpl
index 7cf7fcd..4f91254 100644
--- a/ui/pages/tabs/templates.html.tmpl
+++ b/ui/pages/tabs/templates.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/template-add.html.tmpl b/ui/pages/template-add.html.tmpl
index 75bb0ed..eaafaa7 100644
--- a/ui/pages/template-add.html.tmpl
+++ b/ui/pages/template-add.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
<!DOCTYPE html>
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 5a71d91..d315391 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -18,7 +18,7 @@
#unicode UTF-8
#import gettext
#from kimchi.cachebust import href
-#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang)
+#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
--
2.1.2
10 years
[PATCH] UI: Guest Snapshot
by huoyuxin@linux.vnet.ibm.com
From: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
Signed-off-by: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
---
ui/css/theme-default/guest-edit.css | 34 +++++++++++++-
ui/js/src/kimchi.api.js | 67 +++++++++++++++++++++++++
ui/js/src/kimchi.guest_edit_main.js | 91 +++++++++++++++++++++++++++++++++++
ui/pages/guest-edit.html.tmpl | 25 ++++++++++
4 files changed, 216 insertions(+), 1 deletions(-)
diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index b1d3931..a565c99 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -96,6 +96,7 @@
}
#form-guest-edit-storage .header,
+.guest-edit-snapshot .header,
.guest-edit-interface .header {
margin-bottom: 8px;
padding-bottom: 2px;
@@ -105,6 +106,7 @@
}
#form-guest-edit-storage .body .item,
+.guest-edit-snapshot .body .item,
.guest-edit-interface .body .item {
margin: 5px 0;
}
@@ -115,6 +117,32 @@
width: 250px;
}
+.guest-edit-snapshot .cell {
+ display: inline-block;
+}
+
+.guest-edit-snapshot .sel {
+ width: 35px;
+ vertical-align: top;
+}
+
+.guest-edit-snapshot .icon {
+ background: url('../../images/theme-default/kimchi-loading15x15.gif') no-repeat;
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ vertical-align: middle;
+ margin-left: 2px;
+}
+
+.guest-edit-snapshot .name {
+ width: 400px;
+}
+
+.guest-edit-snapshot .created {
+ width: 250px;
+}
+
#form-guest-edit-storage .cell.dev {
width: 60px;
}
@@ -135,6 +163,7 @@
}
#form-guest-edit-storage .action-area,
+.guest-edit-snapshot .action-area,
.guest-edit-interface .action-area {
float: right;
}
@@ -144,12 +173,14 @@
}
#form-guest-edit-storage button,
+.guest-edit-snapshot button,
.guest-edit-interface button {
width: 20px;
height: 20px;
}
#form-guest-edit-storage .header button,
+.guest-edit-snapshot .header button,
.guest-edit-interface .header button {
margin-bottom: 1px;
}
@@ -159,8 +190,9 @@
margin-right: 2px;
}
+.guest-edit-snapshot .hide,
.guest-edit-interface .hide {
- display: none;
+ display: none!important;
}
.guest-edit-permission {
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 78c6d66..f80f097 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -1260,5 +1260,72 @@ var kimchi = {
kimchi.message.error(data.responseJSON.reason);
}
});
+ },
+
+ listSnapshots : function(vm, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ getCurrentSnapshot : function(vm, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/current',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ revertSnapshot : function(vm, snapshot, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/'+encodeURIComponent(snapshot)+'/revert',
+ type : 'POST',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ createSnapshot : function(vm, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots',
+ type : 'POST',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ deleteSnapshot : function(vm, snapshot, suc, err) {
+ kimchi.requestJSON({
+ url : kimchi.url+'vms/'+encodeURIComponent(vm)+'/snapshots/'+encodeURIComponent(snapshot),
+ type : 'DELETE',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
}
};
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 9d87a73..19fc9ba 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -461,6 +461,96 @@ kimchi.guest_edit_main = function() {
});
};
+ var setupSnapshot = function() {
+ var currentSnapshot;
+ var addItem = function(data, container) {
+ var itemNode = $.parseHTML(kimchi.substitute($('#snapshot-tmpl').html(),data));
+ $("."+container, "#form-guest-edit-snapshot").append(itemNode);
+ $("input:radio", itemNode).click(function(){
+ $(".revert", "#form-guest-edit-snapshot").button(currentSnapshot==data.name?"disable":"enable");
+ });
+ if(kimchi.thisVMState === "running") {
+ $("#form-guest-edit-snapshot .delete").remove();
+ }else{
+ $(".delete", itemNode).button({
+ icons: { primary: "ui-icon-trash" },
+ text: false
+ }).click(function(evt){
+ evt.preventDefault();
+ var item = $(this).parent().parent();
+ kimchi.deleteSnapshot(kimchi.selectedGuest, item.prop("id"), function(){
+ item.remove();
+ });
+ });
+ }
+ return itemNode;
+ };
+ var listGeneratingSnapshots = function(){
+ $(".task", "#form-guest-edit-snapshot").empty();
+ kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/snapshots/*'), function(tasks) {
+ for(var i=0;i<tasks.length;i++){
+ var uri = tasks[i].target_uri;
+ addItem({
+ name: uri.substring(uri.lastIndexOf('/')+1, uri.length),
+ created: "",
+ listMode: "hide",
+ createMode: ""
+ }, 'task');
+ if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1)
+ kimchi.trackTask(tasks[i].id, function(task){
+ listGeneratingSnapshots();
+ listSnapshots();
+ }, function(err){
+ kimchi.message.error(err.message);
+ });
+ }
+ });
+ };
+ var listSnapshots = function(){
+ $(".body", "#form-guest-edit-snapshot").empty();
+ kimchi.listSnapshots(kimchi.selectedGuest, function(data){
+ kimchi.getCurrentSnapshot(kimchi.selectedGuest, function(snapshot){
+ currentSnapshot = snapshot.name;
+ for(var i=0;i<data.length;i++){
+ data[i].created = new Date(data[i].created*1000).toLocaleString();
+ data[i].listMode = "";
+ data[i].createMode = "hide";
+ var item = addItem(data[i], 'body');
+ if(data[i].name==currentSnapshot) $('input:radio', item).prop('checked', true);
+ }
+ });
+ });
+ };
+ listGeneratingSnapshots();
+ listSnapshots();
+ if(kimchi.thisVMState === "running") {
+ $("#form-guest-edit-snapshot .revert").remove();
+ $("#form-guest-edit-snapshot .add").remove();
+ }else{
+ $(".revert", "#form-guest-edit-snapshot").button({
+ icons: { primary: "ui-icon-arrowthick-1-ne" },
+ text: false,
+ disabled: true
+ }).click(function(evt){
+ evt.preventDefault();
+ var item = $("input:radio:checked", "#form-guest-edit-snapshot").parent().parent();
+ kimchi.revertSnapshot(kimchi.selectedGuest, item.prop("id"), function(){
+ currentSnapshot = item.prop("id");
+ $(".revert", "#form-guest-edit-snapshot").button("disable");
+ });
+ });
+ $(".add", "#form-guest-edit-snapshot").button({
+ icons: { primary: "ui-icon-plusthick" },
+ text: false
+ }).click(function(evt){
+ evt.preventDefault();
+ kimchi.createSnapshot(kimchi.selectedGuest, function(){
+ listGeneratingSnapshots();
+ });
+ });
+ }
+ };
+
var initContent = function(guest) {
guest['icon'] = guest['icon'] || 'images/icon-vm.png';
$('#form-guest-edit-general').fillWithObject(guest);
@@ -496,6 +586,7 @@ kimchi.guest_edit_main = function() {
setupInterface();
setupPermission();
setupPCIDevice();
+ setupSnapshot();
kimchi.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
kimchi.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 512909a..796ad42 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -44,6 +44,9 @@
<li>
<a href="#form-guest-edit-pci">$_("Host PCI Device")</a>
</li>
+ <li>
+ <a href="#form-guest-edit-snapshot">$_("Snapshot")</a>
+ </li>
</ul>
<form id="form-guest-edit-general">
<fieldset class="guest-edit-fieldset">
@@ -160,6 +163,17 @@
<div class="body"></div>
</div>
</form>
+ <form id="form-guest-edit-snapshot" class="guest-edit-snapshot">
+ <div class="header">
+ <span class="cell sel"></span>
+ <span class="cell name">$_("Name")</span>
+ <span class="cell created">$_("Created")</span>
+ <button class="add action-area"></button>
+ <button class="revert action-area" title="$_("revert")"></button>
+ </div>
+ <div class="task"></div>
+ <div class="body"></div>
+ </form>
</div>
</div>
<footer>
@@ -251,6 +265,17 @@
<button></button>
</div>
</script>
+<script id="snapshot-tmpl" type="text/html">
+ <div class="item" id="{name}">
+ <span class="cell sel">
+ <span class="icon {createMode}"></span>
+ <input type="radio" name="selSnap" class="{listMode}">
+ </span>
+ <span class="cell name">{name}</span>
+ <span class="cell created">{created}</span>
+ <span class="action-area"><button class="delete {listMode}"></button></span>
+ <div>
+</script>
<script type="text/javascript">
kimchi.guest_edit_main();
</script>
--
1.7.1
10 years
[PATCH V3] Edit Template redefined
by Wen Wang
From: Wen Wang <wenwang(a)linux.vnet.ibm.com>
V2 -> V3:
Fix the bug that iscsi and scsi disk size won't change automatically
V1 -> V2:
1) Enable "iSCSI" and "SCSI" for storage.
2) Changed the storage tab from "storage" to "Storage".
3) Fix the defect that when editing/adding "Storage" or "Interface" line
went down issue.
4) "Storage" and "Interface" content can display properly on Remote and
Image created template.
5) Fix the defect that "Image" didn't show properly when using a Image
created template.
This patch redesigned "Edit Template" diaguage in "Templates". New "Edit
Template" will display all the related information into tabs of
"General", "Storage" and "Interface". Due to unfinished back-end work,
functions are not fully supported, which will be finished in the future
work.
Temporary disabled functions:
1) Multiple disk operation with multiple storage pools edit in template
for which reason the add button in "Storage" tab is disabled.
2) iSCSI and SCSI storage pool add is removed since we are going to
allow this kind of operation in the process of creating a VM.
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
ui/css/theme-default/template-edit.css | 116 +++++++----
ui/js/src/kimchi.template_edit_main.js | 366 +++++++++++++++++++++++---------
ui/pages/template-edit.html.tmpl | 168 ++++++++-------
3 files changed, 434 insertions(+), 216 deletions(-)
diff --git a/ui/css/theme-default/template-edit.css b/ui/css/theme-default/template-edit.css
index 4975f1b..094e909 100644
--- a/ui/css/theme-default/template-edit.css
+++ b/ui/css/theme-default/template-edit.css
@@ -17,24 +17,33 @@
*/
#template-edit-window {
font-size: 13px;
- height: 600px;
- width: 1000px;
+ height: 500px;
+ width: 800px;
}
-.template-edit-fieldset {
- float: left;
- padding: 1em;
+#edit-template-tabs {
+ background: none repeat scroll 0 0 transparent;
+ border: medium none;
+ height: 100%;
+ padding: 0;
}
-.template-edit-wrapper-label, .template-edit-wrapper-controls {
+#edit-template-tabs .form-template-inline-wrapper {
+ display: inline-block;
vertical-align: top;
- width: 470px;
}
.template-edit-wrapper-label {
- height: 18px;
- line-height: 18px;
- margin-top: 8px;
+ vertical-align: top;
+ min-width: 100px;
+ height: 35px;
+ line-height: 35px;
+ margin: 7px 0 8px;
+}
+
+.template-edit-wrapper-controls {
+ vertical-align: top;
+ width: 400px;
}
.template-edit-wrapper-controls input[type="text"] {
@@ -56,7 +65,7 @@
.template-edit-wrapper-controls > .dropdown {
margin: 5px 0 0 1px;
- width: 440px;
+ width: 372px;
}
.template-edit-wrapper-controls input[type="text"][disabled] {
@@ -65,41 +74,72 @@
cursor: not-allowed;
}
-.hidden-area {
- display: none;
+#edit-template-tabs .template-tab-header {
+ margin-bottom: 8px;
+ padding-bottom: 2px;
+ font-weight: bold;
+ border-bottom: 1px solid #999999;
+ overflow: hidden;
}
-.template-edit-wrapper-controls .select-list-box {
- width: 464px;
- max-height: 168px;
- overflow: auto;
- margin-top: 5px;
- border: 1px solid #ccc;
+#edit-template-tabs .template-tab-header .action-area {
+ float: right;
+ height: 20px;
+ width: 20px;
}
-.template-edit-wrapper-controls .select-list-box>li>label {
- display: block;
+#edit-template-tabs .template-interface-cell {
+ display: inline-block;
+ width: 250px;
}
-.template-edit-wrapper-controls .select-list-box>li>label>
-input[type="checkbox"] {
- display: none;
+#edit-template-tabs .template-storage-cell{
+ display: inline-block;
+ width: 230px;
+}
+
+#edit-template-tabs .template-storage-cell label {
+ height: 25px;
+ padding: 2px;
+ border: 1px;
}
-.template-edit-wrapper-controls .select-list-box>li>label>.item {
- display: block;
- height: 41px;
- line-height: 41px;
- padding: 0 20px 0 40px;
- border-bottom: 1px solid #ccc;
- box-shadow: 0px 1px 1px #fff;
- text-shadow: -1px -1px 1px #ddd, 1px 1px 1px #fff;
- color: #222;
- font-size: 12px;
+#form-template-storage .template-tab-body select {
+ width: 140px;
}
-.template-edit-wrapper-controls .select-list-box>li>label>
-input[type="checkbox"]:CHECKED+.item {
- background: #f8f8f8 url(../images/theme-default/check-green.png) no-repeat
- 10px center;
+#form-template-storage .template-tab-body input {
+ width: 56px;
+ height: 17px;
}
+
+#form-template-storage .template-tab-body .template-storage-name {
+ width: 220px;
+}
+
+#edit-template-tabs .template-tab-body input[readonly] {
+ background: none repeat scroll 0 0 rgba(0, 0, 0, 0);
+ border-color: transparent;
+ text-overflow: ellipsis;
+}
+
+#edit-template-tabs .template-tab-body .item {
+ height: 25px;
+}
+
+#form-template-interface .template-tab-body select {
+ width: 180px;
+}
+
+#edit-template-tabs .template-tab-body .action-area {
+ float: right;
+}
+
+#edit-template-tabs .template-tab-body .action-area button {
+ width: 20px;
+ height: 20px;
+}
+
+#edit-template-tabs .hide {
+ display: none;
+}
\ No newline at end of file
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index 2f4cc9a..5073c62 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -16,19 +16,23 @@
* limitations under the License.
*/
kimchi.template_edit_main = function() {
- var templateEditForm = $('#form-template-edit');
+ var templateEditMain = $('#edit-template-tabs');
var origDisks;
var origPool;
+ var origNetworks;
var templateDiskSize;
- $('#template-name', templateEditForm).val(kimchi.selectedTemplate);
- kimchi.retrieveTemplate(kimchi.selectedTemplate, function(template) {
+ $('#template-name', templateEditMain).val(kimchi.selectedTemplate);
+ templateEditMain.tabs();
+
+ var initTemplate = function(template) {
origDisks = template.disks;
origPool = template.storagepool;
+ origNetworks = template.networks;
for(var i=0;i<template.disks.length;i++){
if(template.disks[i].base){
template["vm-image"] = template.disks[i].base;
- $('#templ-edit-cdrom').addClass('hide-content');
- $('#templ-edit-vm-image').removeClass('hide-content');
+ $('.templ-edit-cdrom').addClass('hide');
+ $('.templ-edit-vm-image').removeClass('hide');
break;
}
}
@@ -37,18 +41,12 @@ kimchi.template_edit_main = function() {
if (prop == 'graphics') {
value = value["type"];
}
- $('input[name="' + prop + '"]', templateEditForm).val(value);
- }
- var disks = template.disks;
- $('input[name="disks"]').val(disks[0].size);
- templateDiskSize = $('input[name="disks"]').val();
- if (disks[0].volume) {
- var spool_value = $('#form-template-edit [name="storagepool"]').val();
- $('input[name="storagepool"]', templateEditForm).val(spool_value + '/' + disks[0].volume);
- $('input[name="disks"]', templateEditForm).attr('disabled','disabled');
+ $('input[name="' + prop + '"]', templateEditMain).val(value);
}
var vncOpt = [{label: 'VNC', value: 'vnc'}];
+ $('#template-edit-graphics').append('<option selected>VNC</option>');
+ $('#template-edit-graphics').append('<option>Spice</option>');
kimchi.select('template-edit-graphics-list', vncOpt);
var enableSpice = function() {
if (kimchi.capabilities == undefined) {
@@ -61,119 +59,283 @@ kimchi.template_edit_main = function() {
}
};
enableSpice();
-
- var scsipools = {};
- kimchi.listStoragePools(function(result) {
- var options = [];
- if (result && result.length) {
- $.each(result, function(index, storagePool) {
- if ((storagePool.state=="active") && (storagePool.type !== 'kimchi-iso')) {
- if ((storagePool.type == 'iscsi') || (storagePool.type == 'scsi')){
- scsipools[storagePool.name] = [];
- kimchi.listStorageVolumes(storagePool.name, function(result) {
- if (result && result.length) {
- $.each(result, function(index, storageVolume) {
- options.push({
- label: storagePool.name + '/' + storageVolume.name,
- value: '/storagepools/' + storagePool.name + '/' + storageVolume.name
- });
- scsipools[storagePool.name].push(storageVolume)
- });
- }
- kimchi.select('template-edit-storagePool-list', options);
- });
- }
- else {
- options.push({
- label: storagePool.name,
- value: '/storagepools/' + storagePool.name
- });
- }
+ var initStorage = function(result) {
+ var scsipools = {};
+ var addStorageItem = function(storageData) {
+ var thisName;
+ var thisType;
+ var thisDisk;
+ var nodeStorage = $.parseHTML(kimchi.substitute($('#template-storage-pool-tmpl').html(), storageData));
+ $('.template-tab-body', '#form-template-storage').append(nodeStorage);
+ $('.edit', '#form-template-storage').button({
+ icons : {primary : 'ui-icon-pencil'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ var storageItem = $(this).parent().parent();
+ thisName = $('.template-storage-name', storageItem).val();
+ thisType = $('.template-storage-type', storageItem).val();
+ thisDisk = $('.template-storage-disk', storageItem).val();
+ $('.template-storage-name', storageItem).hide();
+ $('.template-storage-disk', storageItem).attr('readonly', false);
+ if (thisType === 'iscsi' || thisType === 'scsi') {
+ $('.template-storage-disk', storageItem).attr('readonly', true);
+ } else {
+ $('.template-storage-disk', storageItem).attr('readonly', false);
}
+ $('.save', storageItem).parent().show();
+ $('.delete', storageItem).parent().hide();
+ var selectedStorage = $('select', storageItem).val();
+ $('.template-storage-name', storageItem).val(selectedStorage).hide();
+ $('select', storageItem).val(thisName).show();
});
- }
- if ($.isEmptyObject(scsipools)) {
- kimchi.select('template-edit-storagePool-list', options);
- }
- });
- kimchi.listNetworks(function(result) {
- if(result && result.length > 0) {
- var html = '';
- var tmpl = $('#tmpl-network').html();
- $.each(result, function(index, network) {
- if (result[index].state === 'active')
- html += kimchi.substitute(tmpl, network);
+ $('.delete', '#form-template-storage').button({
+ icons : {primary : 'ui-icon-trash'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ $(this).parent().parent().remove();
+ });
+ $('.cancel', '#form-template-storage').button({
+ icons : {primary : 'ui-icon-arrowreturnthick-1-w'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ var cancelEntity = $(this).parent().parent();
+ if ($('.template-storage-name', cancelEntity).val() === 'null') {
+ cancelEntity.remove();
+ } else {
+ $('select', cancelEntity).hide();
+ $('.template-storage-name', cancelEntity).val(thisName).attr('readonly', true).show();
+ $('.template-storage-type', cancelEntity).val(thisType).attr('readonly', true);
+ $('.template-storage-disk', cancelEntity).val(thisDisk).attr('readonly', true);
+ $('.save', cancelEntity).parent().hide();
+ $('.edit', cancelEntity).parent().show();
+ }
+ });
+ $('.save', '#form-template-storage').button({
+ icons : {primary : 'ui-icon-disk'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ var storageItem = $(this).parent().parent();
+ $('.save', storageItem).parent().hide();
+ $('.delete', storageItem).parent().show();
+ var selectedStorage = $('select', storageItem).val();
+ $('.template-storage-name', storageItem).val(selectedStorage).attr('readonly', true).show();
+ $('.template-storage-disk', storageItem).attr('readonly', true);
+ $('.template-storage-type', storageItem).attr('readonly', true);
+ $('select', storageItem).hide();
});
- $('#template-edit-network-list').html(html).show();
- if(template.networks && template.networks.length > 0) {
- $('input[name="networks"]', templateEditForm).each(function(index, element) {
- var value = $(element).val();
- if(template.networks.indexOf(value) >= 0) {
- $(element).prop('checked', true);
+ var storageOptions = '';
+ var scsiOptions = '';
+ $('select', '#form-template-storage').find('option').remove();
+ $.each(result, function(index, storageEntities) {
+ if((storageEntities.state === 'active') && (storageEntities.type != 'kimchi-iso')) {
+ if(storageEntities.type === 'iscsi' || storageEntities.type === 'scsi') {
+ kimchi.listStorageVolumes(storageEntities.name, function(currentVolume) {
+ $.each(currentVolume, function(indexSCSI, scsiEntities) {
+ scsiOptions += '<option>' + storageEntities.name + '/' + scsiEntities.name + '</option>';
+ });
+ $('select', '#form-template-storage').append(scsiOptions);
+ }, function() {});
+ } else {
+ var isSlected = storageEntities.name === 'default' ? ' selected' : '';
+ storageOptions += '<option' + isSlected + '>' + storageEntities.name + '</option>';
+ }
+ }
+ });
+ $('select', '#form-template-storage').append(storageOptions);
+ $('select', '#form-template-storage').change(function() {
+ var selectedItem = $(this).parent().parent();
+ var tempStorageName = $(this).val();
+ var tempType;
+ tempStorageName =tempStorageName.split('/')[0];
+ var scsiCap;
+ $.each(result, function(index, storageEntities) {
+ if (tempStorageName === storageEntities.name) {
+ selectedItem.find('.template-storage-type').val(storageEntities.type);
+ scsiCap = storageEntities.capacity / Math.pow(1024, 3);
+ tempType = storageEntities.type;
}
});
+ if (tempType === 'iscsi' || tempType === 'scsi') {
+ $('.template-storage-disk', selectedItem).attr('readonly', true).val(scsiCap);
+ } else {
+ $('.template-storage-disk', selectedItem).attr('readonly', false).val('10');
+ }
+ });
+ };
+
+ if ((origDisks && origDisks.length) && (origPool && origPool.length)) {
+ splitPool = origPool.split('/');
+ var defaultPool;
+ var defaultType;
+ $.each(result, function(index, poolEntities) {
+ if (poolEntities.name === splitPool[splitPool.length-1]) {
+ defaultType = poolEntities.type;
+ defaultPool = splitPool[splitPool.length-1]
+ }
+ });
+ if (origDisks[0]['volume']) {
+ defaultPool = defaultPool + '/' + origDisks[0]['volume'];
}
- } else {
- $('#template-edit-network-list').hide();
+ $.each(origDisks, function(index, diskEntities) {
+ var storageNodeData = {
+ viewMode : '',
+ editMode : 'hide',
+ storageName : defaultPool,
+ storageType : defaultType,
+ storageDisk : diskEntities.size
+ }
+ addStorageItem(storageNodeData);
+ });
+ $('.template-storage-disk').attr('readonly', true);
}
- });
- });
- $('#template-edit-storagePool').change(function() {
- storagepool = $(this).val();
- var storageArray = storagepool.split("/");
- if (storageArray.length > 3) {
- volumeName = storageArray.pop();
- poolName = storageArray.pop();
- kimchi.getStoragePoolVolume(poolName, volumeName, function(result) {
- $('input[name="disks"]', templateEditForm).val(result.capacity / Math.pow(1024,3));
- $('input[name="disks"]', templateEditForm).attr('disabled','disabled');
- return false;
- }, function (err) {
- kimchi.message.error(err.responseJSON.reason);
+ $('#template-edit-storage-add-button').button({
+ icons: {
+ primary: "ui-icon-plusthick"
+ },
+ text: false,
+ disabled: true
+ }).click(function(event) {
+ event.preventDefault();
+ var storageNodeData = {
+ viewMode : 'hide',
+ editMode : '',
+ storageName : 'null',
+ storageType : 'dir',
+ storageDisk : '10'
+ }
+ addStorageItem(storageNodeData);
});
- } else {
- $('input[name="disks"]', templateEditForm).removeAttr('disabled');
- $('input[name="disks"]', templateEditForm).val(templateDiskSize);
- }
- });
- $('input[name="disks"]', templateEditForm).keyup(function() {
- templateDiskSize = $('input[name="disks"]', templateEditForm).val();
- });
+ };
+ var initInterface = function(result) {
+ var addInterfaceItem = function(networkData) {
+ var nodeInterface = $.parseHTML(kimchi.substitute($('#template-interface-tmpl').html(), networkData));
+ $('.template-tab-body', '#form-template-interface').append(nodeInterface);
+ $('.edit', '#form-template-interface').button({
+ icons : {primary : 'ui-icon-pencil'},
+ text : false,
+ disabled : true
+ });
+ $('.delete', '#form-template-interface').button({
+ icons : {primary : 'ui-icon-trash'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ $(this).parent().parent().remove();
+ });
+ $('.cancel', '#form-template-interface').button({
+ icons : {primary : 'ui-icon-arrowreturnthick-1-w'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ $(this).parent().parent().remove();
+ });
+ $('.save', '#form-template-interface').button({
+ icons : {primary : 'ui-icon-disk'},
+ text : false
+ }).click(function(evt) {
+ evt.preventDefault();
+ var interItem = $(this).parent().parent();
+ $('.save', interItem).parent().hide();
+ $('.delete', interItem).parent().show();
+ var selectedInterface = $('select', interItem).val();
+ $('.template-interface-name', interItem).val(selectedInterface).show();
+ $('select', interItem).hide();
+ });
+ var networkOptions = '';
+ for(var i=0;i<result.length;i++){
+ if(result[i].state === "active") {
+ var isSlected = i==0 ? ' selected' : '';
+ networkOptions += '<option' + isSlected + '>' + result[i].name + '</option>';
+ }
+ }
+ $('select', '#form-template-interface').find('option').remove();
+ $('select', '#form-template-interface').append(networkOptions);
+ };
+ if(result && result.length > 0) {
+ $.each(result, function(index, data) {
+ if($.inArray(data.name, origNetworks) > -1) {
+ addInterfaceItem({
+ mac : '',
+ network : data.name,
+ type : 'network',
+ viewMode : '',
+ editMode : 'hide'
+ });
+ }
+ });
+ }
+ $('#template-edit-interface-add-button').button({
+ icons: {
+ primary: 'ui-icon-plusthick'
+ },
+ text: false
+ }).click(function(evt) {
+ evt.preventDefault();
+ addInterfaceItem({
+ mac : '',
+ network : '',
+ type : 'network',
+ viewMode : 'hide',
+ editMode : ''
+ });
+ });
+ };
+ kimchi.listNetworks(initInterface);
+ kimchi.listStoragePools(initStorage);
+ };
+ kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate);
+
$('#tmpl-edit-button-save').on('click', function() {
- var editableFields = [ 'name', 'cpus', 'memory', 'storagepool', 'disks', 'graphics'];
+ var editableFields = [ 'name', 'cpus', 'memory', 'disks', 'graphics'];
var data = {};
+ //Fix me: Only support one storage pool now
+ var storages = $('.template-tab-body .item', '#form-template-storage');
+ var tempName = $('.template-storage-name', storages).val();
+ tempName = tempName.split('/');
+ var tempNameHead =tempName[0];
+ var tempNameTail = tempNameHead;
+ if(tempNameHead === 'iscsi' || tempNameHead =='scsi') {
+ tempNameTail = tempName[tempName.length-1];
+ }
+ tempName = '/storagepools/' + tempNameHead;
+ data['storagepool'] = tempName;
$.each(editableFields, function(i, field) {
/* Support only 1 disk at this moment */
if (field == 'disks') {
- origDisks[0].size = Number($('#form-template-edit [name="' + field + '"]').val());
+ var tmpItem = $('#form-template-storage .item');
+ origDisks[0].size = Number($('.template-storage-disk', tmpItem).val());
+ if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() =='scsi') {
+ origDisks[0]['volume'] = tempNameTail;
+ } else {
+ origDisks[0]['volume'] && delete origDisks[0]['volume'];
+ }
data[field] = origDisks;
}
else if (field == 'graphics') {
- var type = $('#form-template-edit [name="' + field + '"]').val();
+ var type = $('#form-template-general [name="' + field + '"]').val();
data[field] = {'type': type};
}
else {
- data[field] = $('#form-template-edit [name="' + field + '"]').val();
+ data[field] = $('#form-template-general [name="' + field + '"]').val();
}
});
data['memory'] = Number(data['memory']);
data['cpus'] = Number(data['cpus']);
- storagepool = data['storagepool'];
- storageArray = storagepool.split("/");
- if (storageArray.length > 3){
- /* Support only 1 disk at this moment */
- data["disks"][0].volume = storageArray.pop();
- data['storagepool'] = storageArray.join("/");
- } else if (data["disks"][0].volume) {
- delete data["disks"][0].volume;
- }
- var networks = templateEditForm.serializeObject().networks;
- if (networks instanceof Array) {
- data.networks = networks;
- } else if (networks != null) {
- data.networks = [networks];
+ var networks = $('.template-tab-body .item', '#form-template-interface');
+ var networkForUpdate = new Array();
+ $.each(networks, function(index, networkEntities) {
+ networkForUpdate.push($('.template-interface-name', networkEntities).val());
+ });
+ if (networkForUpdate instanceof Array) {
+ data.networks = networkForUpdate;
+ } else if (networkForUpdate != null) {
+ data.networks = [networkForUpdate];
} else {
data.networks = [];
}
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 5a71d91..018ac10 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -28,74 +28,67 @@
<div class="close">X</div>
</header>
<div class="content">
- <form id="form-template-edit">
+ <div id="edit-template-tabs">
<input type="hidden" id="template-name" name="templateName" />
- <fieldset class="template-edit-fieldset">
- <div>
+ <ul>
+ <li>
+ <a href="#form-template-general">$_("General")</a>
+ </li>
+ <li>
+ <a href="#form-template-storage">$_("Storage")</a>
+ </li>
+ <li>
+ <a href="#form-template-interface">$_("Interface")</a>
+ </li>
+ </ul>
+ <form id="form-template-general">
+ <div class="form-template-inline-wrapper">
<div class="template-edit-wrapper-label">
<label for="template-edit-id-textbox">$_("Name")</label>
</div>
- <div class="template-edit-wrapper-controls">
- <input id="template-edit-id-textbox" name="name" type="text" />
- </div>
- </div>
- <div>
<div class="template-edit-wrapper-label">
<label for="template-edit-vendor-textbox">$_("Vendor")</label>
</div>
- <div class="template-edit-wrapper-controls">
- <input id="template-edit-vendor-textbox" name="os_distro" type="text" disabled="disabled" />
- </div>
- </div>
- <div>
<div class="template-edit-wrapper-label">
<label for="template-edit-version-textbox">$_("Version")</label>
</div>
- <div class="template-edit-wrapper-controls">
- <input id="template-edit-version-textbox" name="os_version" type="text" disabled="disabled" />
- </div>
- </div>
- <div>
<div class="template-edit-wrapper-label">
<label for="template-edit-cpu-textbox">$_("CPU Number")</label>
</div>
- <div class="template-edit-wrapper-controls">
- <input id="template-edit-cpu-textbox" name="cpus" type="text" />
- </div>
- </div>
- <div>
<div class="template-edit-wrapper-label">
<label for="template-edit-memory-textbox">$_("Memory (MB)")</label>
</div>
- <div class="template-edit-wrapper-controls">
- <input id="template-edit-memory-textbox" name="memory" type="text" />
+ <div class="template-edit-wrapper-label templ-edit-cdrom">
+ <label for="template-edit-cdrom-textbox">$_("CDROM")</label>
+ </div>
+ <div class="template-edit-wrapper-label templ-edit-vm-image hide">
+ <label for="template-edit-vmimage-textbox">$_("Image File")</label>
</div>
- </div>
- <div>
<div class="template-edit-wrapper-label">
- <label for="template-edit-disk-textbox">$_("Disk (GB)")</label>
+ <label>$_("Graphics")</label>
</div>
+ </div>
+ <div class="form-template-inline-wrapper">
<div class="template-edit-wrapper-controls">
- <input id="template-edit-disk-textbox" name="disks" type="text" />
+ <input id="template-edit-id-textbox" name="name" type="text" />
</div>
- </div>
- </fieldset>
- <fieldset class="template-edit-fieldset">
- <div id="templ-edit-cdrom">
- <div class="template-edit-wrapper-label">
- <label for="template-edit-cdrom-textbox">$_("CDROM")</label>
+ <div class="template-edit-wrapper-controls">
+ <input id="template-edit-vendor-textbox" name="os_distro" type="text" disabled="disabled" />
</div>
<div class="template-edit-wrapper-controls">
- <input id="template-edit-cdrom-textbox" name="cdrom" type="text" disabled="disabled"/>
+ <input id="template-edit-version-textbox" name="os_version" type="text" disabled="disabled" />
</div>
- </div>
- <div id="templ-edit-vm-image" class="hide-content">
- <div class="template-edit-wrapper-label">$_("Image File")</div>
- <div class="template-edit-wrapper-controls"><input name="vm-image" type="text" disabled/></div>
- </div>
- <div>
- <div class="template-edit-wrapper-label">
- <label>$_("Graphics")</label>
+ <div class="template-edit-wrapper-controls">
+ <input id="template-edit-cpu-textbox" name="cpus" type="text" />
+ </div>
+ <div class="template-edit-wrapper-controls">
+ <input id="template-edit-memory-textbox" name="memory" type="text" />
+ </div>
+ <div class="template-edit-wrapper-controls templ-edit-cdrom">
+ <input id="template-edit-cdrom-textbox" name="cdrom" type="text" disabled="disabled" />
+ </div>
+ <div class="template-edit-wrapper-controls templ-edit-vm-image hide">
+ <input id="template-edit-vmimage-textbox" name="vm-image" type="text" disabled="disabled" />
</div>
<div class="template-edit-wrapper-controls">
<div class="btn dropdown popable">
@@ -108,40 +101,26 @@
</div>
</div>
</div>
- <div>
- <div class="template-edit-wrapper-label">
- <label>$_("Storage Pool")</label>
- </div>
- <div class="template-edit-wrapper-controls">
- <div class="btn dropdown popable">
- <input id="template-edit-storagePool" name="storagepool" type="hidden" />
- <span class="text" id="template-edit-storage-label"></span><span class="arrow"></span>
- <div class="popover" style="width: 100%">
- <ul class="select-list" id="template-edit-storagePool-list" data-target="template-edit-storagePool" data-label="template-edit-storage-label">
- </ul>
- </div>
- </div>
- </div>
+ </form>
+ <form id="form-template-storage">
+ <div class="template-tab-header">
+ <span class="template-storage-cell">$_("Storage Pool")</span>
+ <span class="template-storage-cell">$_("Type")</span>
+ <span class="template-storage-cell">$_("Disk(GB)")</span>
+ <button type="button" id="template-edit-storage-add-button" class="action-area"></button>
</div>
- <div>
- <div class="template-edit-wrapper-label">
- <label>$_("Network")</label>
- </div>
- <div class="template-edit-wrapper-controls">
- <ul class="select-list-box" id="template-edit-network-list">
- </ul>
- <script id="tmpl-network" type="text/html">
- <li>
- <label>
- <input name="networks" type="checkbox" value="{name}" />
- <span class="item">{name}</span>
- </label>
- </li>
- </script>
- </div>
+ <div class="template-tab-body">
</div>
- </fieldset>
- </form>
+ </form>
+ <form id="form-template-interface">
+ <div class="template-tab-header">
+ <span class="template-interface-cell">$_("Network")</span>
+ <span class="template-interface-cell">$_("Type")</span>
+ <button type="button" id="template-edit-interface-add-button" class="action-area"></button>
+ </div>
+ <div class="template-tab-body"></div>
+ </form>
+ </div>
</div>
<footer>
<div class="btn-group">
@@ -152,3 +131,40 @@
<script>
kimchi.template_edit_main();
</script>
+<script id="template-storage-pool-tmpl" type="text/html">
+ <div class='item'>
+ <span class="template-storage-cell">
+ <input class="template-storage-name {viewMode}" value={storageName} readonly=true type="text"/>
+ <select class="{editMode}"></select>
+ </span>
+ <span class="template-storage-cell">
+ <input class="template-storage-type" value={storageType} readonly=true type="text" />
+ </span>
+ <span class="template-storage-cell">
+ <input class="template-storage-disk" value={storageDisk} type="text" />
+ </span>
+ <span class="action-area {editMode}">
+ <button class="save"></button><button class="cancel"></button>
+ </span>
+ <span class="action-area {viewMode}">
+ <button class="edit"></button><button class="delete"></button>
+ </span>
+ </div>
+</script>
+<script id="template-interface-tmpl" type="text/html">
+ <div class="item">
+ <span class="template-interface-cell">
+ <input class="template-interface-name {viewMode}" readonly="true" type="text" value={network} />
+ <select class="{editMode}"></select>
+ </span>
+ <span class="template-interface-cell">
+ <input value={type} readonly=true type="text" />
+ </span>
+ <span class="action-area {editMode}">
+ <button class="save"></button><button class="cancel"></button>
+ </span>
+ <span class="action-area {viewMode}">
+ <button class="edit"></button><button class="delete"></button>
+ </span>
+ </div>
+</script>
\ No newline at end of file
--
1.7.1
10 years
[PATCHv4 0/8] LDAP support in backend
by lvroyce@linux.vnet.ibm.com
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
v3>v4,
Move authentication type report to capabilities.
Be back compatible for old access label.
Change try/exception logic in ldap authentication.
Royce Lv (8):
Add configuration of LDAP
Split PAM and LDAP authentication
Add LDAP authentication
Fix test cases for authentication
Split users and groups for permission query
Move validation to authorizaiton
change vm permission tag
Update test model to fix user/group listing
contrib/DEBIAN/control.in | 1 +
contrib/kimchi.spec.fedora.in | 1 +
contrib/kimchi.spec.suse.in | 1 +
docs/API.md | 20 +++---
docs/README.md | 36 +++++-----
src/kimchi.conf.in | 17 +++++
src/kimchi/auth.py | 155 +++++++++++++++++++++++++++++++-----------
src/kimchi/config.py.in | 5 ++
src/kimchi/control/auth.py | 42 ++++++++++++
src/kimchi/control/host.py | 14 ----
src/kimchi/i18n.py | 1 +
src/kimchi/model/config.py | 1 +
src/kimchi/model/groups.py | 68 ++++++++++++++++++
src/kimchi/model/host.py | 19 ------
src/kimchi/model/users.py | 90 ++++++++++++++++++++++++
src/kimchi/model/vms.py | 62 ++++++++++++-----
tests/test_model.py | 3 +-
tests/test_rest.py | 4 +-
tests/utils.py | 43 ++++++++----
19 files changed, 451 insertions(+), 132 deletions(-)
create mode 100644 src/kimchi/control/auth.py
create mode 100644 src/kimchi/model/groups.py
create mode 100644 src/kimchi/model/users.py
--
1.8.3.2
10 years
[PATCH v4] Auto Topology for Guest Templates
by Christy Perez
This is another rework of how this flow should work, after more thought and
discussion with Aline.
This new flow removes the 'auto-topology' element from the API and makes it so that
users can enter varying information without being dinged for not doing exactly the
right thing (e.g. vcpus != sockets * cores * threads).
It also works in a way that doesn't require the UI to have access to the kimchi Model objects (as I misremembered for the previous patches).
1. UI calls GET host/cpuinfo
curl -k -u user -H 'Content-Type: application/json' \
-H 'Accept: application/json' https://localhost:8001/host/cpuinfo
{
"cores":2,
"threading_enabled":true,
"sockets":1,
"threads_per_core":2
}
2. UI displays appropriate title and checkboxes
- If host arch is Power:
- Display a menu labled SMT, with up to four check-boxes.
The check-boxes will be labeled SMT1, SMT2, SMT4, and SMT8.
The max SMT value displayed will be dependant upon
threads_per_core from above. The default checkbox should be the
greatest SMT value (e.g. SMT8).
- Display the same box for CPUs as before. This value may change
when the backend template creation is done, so if there's any way
to pop up "Here are the values of your new template," kind of message,
that would be nice. Otherwise, we'll just make it clear in the doc
that the vCPUs value entered is not guaranteed.
- Else:
- Display a menu labeled Hyper-Threading, with only a checkbox labeled
HT.
Note: The same comments for vCPUS as above apply here. The number
maybe need to change based on the CPU capabilities.
3. UI calls POST template with threads value set to '0' (x86) or SMTX (Power)
Note that vcpus is still optional, so no change in how that's handled needs
to be done.
$ curl -k -u user -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' https://localhost:8001/templates -d'{"name": "test_auto_topo", "cdrom": "/home/iso-pool/Fedora-Live-Desktop-x86_64-20-1.iso", "cpu_info": {"topology": {"threads":0}}}'
{
"cpus":1,
"cpu_info":{
"topology":{
"cores":1,
"threads":1,
"sockets":1
}
},
"graphics":{
"type":"vnc",
"listen":"127.0.0.1"
},
"cdrom":"/home/iso-pool/Fedora-Live-Desktop-x86_64-20-1.iso",
"networks":[
"default"
],
"icon":"images/icon-fedora.png",
"os_distro":"fedora",
"name":"test_auto_topo",
"disks":[
{
"index":0,
"size":10
}
],
"invalid":{},
"os_version":"20",
"storagepool":"/storagepools/default",
"memory":1024,
"folder":[]
}
Regards,
- Christy
Christy Perez (1):
Parts to allow Kimchi to configure the cpu topology.
docs/API.md | 28 +++++++
src/kimchi/API.json | 11 +--
src/kimchi/control/cpuinfo.py | 37 +++++++++
src/kimchi/control/host.py | 2 +
src/kimchi/i18n.py | 3 +-
src/kimchi/model/cpuinfo.py | 172 ++++++++++++++++++++++++++++++++++++++++++
src/kimchi/model/host.py | 1 +
src/kimchi/model/templates.py | 25 ++++--
8 files changed, 263 insertions(+), 16 deletions(-)
create mode 100644 src/kimchi/control/cpuinfo.py
create mode 100644 src/kimchi/model/cpuinfo.py
--
1.9.3
10 years
[PATCH] Improve french translation
by Cédric Bosdonnat
Contains a few typos fixes and a bunch of new translations.
---
po/fr_FR.po | 152 ++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 87 insertions(+), 65 deletions(-)
diff --git a/po/fr_FR.po b/po/fr_FR.po
index cfc0c44..6ee4f45 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -19,7 +19,7 @@ msgstr ""
#, python-format
msgid "Unknown parameter %(value)s"
-msgstr ""
+msgstr "Paramètre inconnu %(value)s"
#, python-format
msgid "Delete is not allowed for %(resource)s"
@@ -37,7 +37,7 @@ msgstr ""
#, python-format
msgid "Create is not allowed for %(resource)s"
-msgstr "La créatio n'est pas autorisée pour %(resource)s"
+msgstr "La création n'est pas autorisée pour %(resource)s"
msgid "Unable to parse JSON request"
msgstr "Impossible de parser la requête JSON"
@@ -68,20 +68,20 @@ msgstr ""
"d'Erreur: %(code)s]"
msgid "You are not authorized to access Kimchi"
-msgstr "Vous n'êtes pas autorisé à accéder à Kimchi"
+msgstr "Vous n'êtes pas autorisé à accéder à Kimchi"
#, python-format
msgid "Specify %(item)s to login into Kimchi"
msgstr "Spécifiez %(item)s pour vous logguer dans Kimchi"
msgid "Unknown \"_cap\" specified"
-msgstr ""
+msgstr "\"_cap\" spécifiée inconnue"
msgid "\"_passthrough\" should be \"true\" or \"false\""
-msgstr ""
+msgstr "\"_passthrough\" doit être \"true\" ou \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
-msgstr ""
+msgstr "\"_passthrough_affected_by\" doit être un nom de périphérique"
#, python-format
msgid "Error while getting block devices. Details: %(err)s"
@@ -115,7 +115,7 @@ msgstr "Impossible de se connecter à l'hôte iSCSI %(host)s cible %(target)s"
#, python-format
msgid "Unable to find ISO file %(filename)s"
-msgstr ""
+msgstr "Impossible de trouver le fichier ISO %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
@@ -161,20 +161,22 @@ msgstr ""
"%(err)s"
msgid "An error occurred when probing image OS information."
-msgstr ""
+msgstr "Une erreur est survenue lors de la détection de l'information d'OS de l'image."
msgid "No OS information found in given image."
msgstr "Aucune information d'OS trouvée sur l'image donnée."
#, python-format
msgid "Unable to read image file %(filename)s"
-msgstr ""
+msgstr "Impossible de lire le fichier image %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
+"Le fichier image doit être un fichier existant sur le système. %(filename)s n'est "
+"pas une donnée valide."
#, python-format
msgid "Virtual machine %(name)s already exists"
@@ -189,6 +191,8 @@ msgid ""
"Unable to rename virtual machine %(name)s. The name %(new_name)s is already "
"in use or the virtual machine is not powered off."
msgstr ""
+"Impossible de renommer la machine virtuelle %(name)s. Le nom %(new_name)s est "
+"déja utilisé ou la machine virtuelle n'est pas éteinte."
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
@@ -201,7 +205,7 @@ msgstr "L'image ISO distante n'est pas supportée par le serveur."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
-msgstr ""
+msgstr "Copie d'écran non supportée par la machine virtuelle %(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
@@ -219,7 +223,7 @@ msgstr ""
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
-msgstr ""
+msgstr "Impossible de se connecter à la machine virtuelle éteinte %(name)s."
msgid "Virtual machine name must be a string"
msgstr "Le nom de la machine virtuelle doit être une chaîne de caractères."
@@ -293,19 +297,23 @@ msgstr ""
"%(err)s"
msgid "The guest console password must be a string."
-msgstr ""
+msgstr "Le mot de passe de console invitée doit être une chaîne de caractères."
msgid "The life time for the guest console password must be a number."
-msgstr ""
+msgstr "La durée de vie du mot de passe de console invitée doit être un nombre"
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
+"La machine virtuelle %(vmid)s ne peut pas contenir le périphérique hôte "
+"directement assigné %(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
+"The périphérique hôte %(dev_name)s ne peut être directement assigné à "
+"la machine virtuelle"
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
@@ -316,7 +324,7 @@ msgid ""
msgstr ""
msgid "\"name\" should be a device name string"
-msgstr ""
+msgstr "\"name\" doit être un nom de périphérique"
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
@@ -430,7 +438,7 @@ msgstr ""
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
-msgstr ""
+msgstr "Le volume %(volume)s n'est pas dans le pool de stockage %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
@@ -441,7 +449,7 @@ msgid "Unable to delete template due error: %(err)s"
msgstr "Impossilbe de supprimer le modèle à cause de l'erreur: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
-msgstr ""
+msgstr "La taille de disque doit être un entier supérieur à 1Go."
msgid "Template base image must be a valid local image file"
msgstr "L'image de base de modèle doit petre un fichier image local valide"
@@ -458,7 +466,8 @@ msgstr ""
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
-msgstr ""
+msgstr "Dans la topologie de CPU, chaque élément doit être un entier "
+"strictement positif."
#, python-format
msgid "Storage pool %(name)s already exists"
@@ -534,6 +543,8 @@ msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
+"Les types de pool de stockage supportés sont: dir, netfs, logical, "
+"iscsi, isci et kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "Le chemin du pool de stockage doit être une chaîne de caractères"
@@ -556,10 +567,10 @@ msgstr ""
"et 65535"
msgid "iSCSI target username must be a string"
-msgstr ""
+msgstr "Le nom d'utilisateur de la cible iSCSI doit être une chaîne de caractères"
msgid "iSCSI target password must be a string"
-msgstr ""
+msgstr "Le mot de passe de la cible iSCSI doit être une chaîne de caractères"
msgid "Specify name and type to create a storage pool"
msgstr "Spécifier un nom et un type pour créer un pool de stockage"
@@ -574,7 +585,7 @@ msgstr ""
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
-msgstr ""
+msgstr "Impossible d'agrandir le pool logique %(pool)s. Détails: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
@@ -644,6 +655,8 @@ msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
+"Impossible de créer le volume de stockage %(volume)s car le pool de "
+"stockage %(pool)s n'est pas actif"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
@@ -720,21 +733,21 @@ msgstr ""
#, python-format
msgid "Only one of parameter %(param)s can be specified"
-msgstr ""
+msgstr "Seulement un seul des paramêtre %(param)s peut être spécifié"
#, python-format
msgid "Create volume from %(param)s is not supported"
-msgstr ""
+msgstr "La création de volume avec %(param)s n'est pas supportée"
msgid "Storage volume capacity must be an integer number."
-msgstr ""
+msgstr "La capacité du volume de stockage doit être un nombre entier."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
-msgstr ""
+msgstr "L'URL du volume de stockage doit être http://, https://, ftp:// ou ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
-msgstr ""
+msgstr "Impossible d'accéder au fichier %(url)s. Veuillez le vérifier."
#, python-format
msgid "Interface %(name)s does not exist"
@@ -833,7 +846,7 @@ msgstr ""
#, python-format
msgid "Debug report %(name)s does not exist"
-msgstr "LE rapport de déboggage %(name)s n'existe pas"
+msgstr "Le rapport de déboggage %(name)s n'existe pas"
msgid "Debug report tool not found in system"
msgstr "L'outil de rapport de déboggage n'a pas été trouvé dans le système"
@@ -846,6 +859,7 @@ msgstr ""
#, python-format
msgid "Can not find any debug report with the given name %(name)s"
msgstr ""
+"Impossible de trouver un rapport de déboggage avec le nom fourni %(name)s"
#, python-format
msgid "Unable to generate debug report %(name)s. Details: %(err)s"
@@ -853,12 +867,14 @@ msgstr ""
"Impossible de générer le rapport de déboggage %(name)s. Détails: %(err)s"
msgid "You should give a name for the debug report file."
-msgstr ""
+msgstr "Vous devriez donner un nom au fichier de rapport de déboggage."
msgid ""
"Debug report name must be a string. Only letters, digits, underscore ('_') "
"and hyphen ('-') are allowed."
msgstr ""
+"Le nom du rapport de déboggage doit être une chaîne de caractères. Seulement "
+"les lettres, chiffres, blanc souligné ('_') et tirets ('-') sont acceptés."
#, python-format
msgid ""
@@ -882,12 +898,12 @@ msgstr "La partition %(name)s n'existe pas sur cet hôte"
msgid "Unable to shutdown host machine as there are running virtual machines"
msgstr ""
-"Impossilbe d'éteindre la machine hôte car des machines virtuelles en sont "
+"Impossible d'éteindre la machine hôte car des machines virtuelles en sont "
"cours d'exécution"
msgid "Unable to reboot host machine as there are running virtual machines"
msgstr ""
-"Impossilbe de rebooter la machine hôte car des machines virtuelles en sont "
+"Impossible de redémarrer la machine hôte car des machines virtuelles en sont "
"cours d'exécution"
#, python-format
@@ -895,7 +911,7 @@ msgid "Node device '%(name)s' not found"
msgstr "Périphérique de noeud '%(name)s' non trouvé"
msgid "Conflicting flag filters specified."
-msgstr ""
+msgstr "Filtres incompatibles spécifiés."
msgid "No packages marked for update"
msgstr "Aucun paquet marqué pour mise à jour"
@@ -928,7 +944,7 @@ msgstr ""
"secondes"
msgid "Unable to choose a virtual machine name"
-msgstr ""
+msgstr "Impossible de sélectionner un nom de machine virtuelle"
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Type de stockage invalide. Les Types supportés sont: 'cdrom', 'disk'"
@@ -938,13 +954,15 @@ msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
msgid "Only CDROM path can be update."
-msgstr ""
+msgstr "Seulement le chemin d'un CDROM peut être modifié."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
+"Le périphérique de stockage %(dev_name)s n'existe pas dans la machine virtuelle "
+"%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
@@ -960,7 +978,7 @@ msgid "Error while removing storage device: %(error)s"
msgstr "Erreur durant le retrait du périphérique de stockage: %(error)s"
msgid "Do not support IDE device hot plug"
-msgstr ""
+msgstr "Ne pas supporter le branchement à chaud de périphérique IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
@@ -997,6 +1015,8 @@ msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
+"Le volume de format %(format)s sélectionné ne correspond pas "
+"au type de stockage %(type)s"
msgid "YUM Repository ID must be one word only string."
msgstr ""
@@ -1106,7 +1126,7 @@ msgstr "Impossible de supprimer un dépôt. Détails: '%(err)s'"
#, python-format
msgid ""
"Configuration items: '%(items)s' are not supported by repository manager"
-msgstr ""
+msgstr "Éléments de configurations: %(items)s ne sont pas supportés par le gestionnaire de dépôt"
msgid "ERROR CODE"
msgstr "ERROR CODE"
@@ -1176,7 +1196,7 @@ msgid "Permission"
msgstr "Permission"
msgid "Host PCI Device"
-msgstr ""
+msgstr "Périphérique PCI Hôte"
msgid "Name"
msgstr "Nom"
@@ -1212,16 +1232,16 @@ msgid "All"
msgstr "Tous"
msgid "To Add"
-msgstr ""
+msgstr "À Ajouter"
msgid "Added"
-msgstr ""
+msgstr "Ajouter"
msgid "filter"
-msgstr ""
+msgstr "Filtre"
msgid "Product"
-msgstr ""
+msgstr "Produit"
msgid "Vendor"
msgstr "Vendeur"
@@ -1352,13 +1372,13 @@ msgid "Warning"
msgstr "Avertissement"
msgid "Creating..."
-msgstr ""
+msgstr "Création en cours..."
msgid "Loading..."
msgstr "Chargement en cours..."
msgid "An error occurred while checking for packages update."
-msgstr ""
+msgstr "Une erreur est survenue lors de la vérification des mises-à-jour de paquets."
msgid "Retry"
msgstr "Essayer à nouveau"
@@ -1367,7 +1387,7 @@ msgid "Detailed message:"
msgstr "Message détaillé:"
msgid "No ISO found"
-msgstr ""
+msgstr "Aucune ISO détectée"
msgid "This is not a valid ISO file."
msgstr "Ce n'est pas un fichier ISO valide."
@@ -1477,7 +1497,7 @@ msgid "Updating..."
msgstr "En cours de mise à jour..."
msgid "Failed to retrieve packages update information."
-msgstr ""
+msgstr "Échec de récupération des informations de mise-à-jour des paquets."
msgid "Failed to update package(s)."
msgstr "Échec durant la mise à jour du/des paquet(s)"
@@ -1518,7 +1538,7 @@ msgid "Pending..."
msgstr "En attente..."
msgid "Report name is the same as the original one."
-msgstr ""
+msgstr "Le nom du rapport est le même que celui d'origine."
msgid ""
"This will delete the virtual machine and its virtual disks. This operation "
@@ -1555,7 +1575,7 @@ msgstr ""
"Noter que l'OS invité pourrait ignorer cette requête. Voulez-vous continuer ?"
msgid "Virtual Machine delete Confirmation"
-msgstr ""
+msgstr "Confirmation de suppression de Machine Virtuelle"
msgid ""
"This virtual machine is not persistent. Power Off will delete it. Continue?"
@@ -1587,6 +1607,8 @@ msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
+"Ce disque sera définitivement détaché et peut être ré-attaché. Continuer "
+"à le détacher ?"
msgid "The VLAN id must be between 1 and 4094."
msgstr "L'id du VLAN doit être entre 1 et 4094."
@@ -1686,13 +1708,13 @@ msgid "Unable to retrieve partitions information."
msgstr "Impossible de récupérer les informations des partitions."
msgid "In progress..."
-msgstr ""
+msgstr "En cours..."
msgid "Failed!"
-msgstr ""
+msgstr "Échec!"
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
-msgstr ""
+msgstr "Le chemin de CDROM doit être un chemin local/distant valide et ne peut être virge."
msgid "Disk pool or volume cannot be blank."
msgstr "Le pool de disque ou le volume ne peut être vierge."
@@ -1719,7 +1741,7 @@ msgid "Version:"
msgstr "Version:"
msgid "Session timeout, please re-login."
-msgstr "Session expirée, veuillez vous reconecter."
+msgstr "Session expirée, veuillez vous reconnecter."
msgid "User Name"
msgstr "Nom d'Utilisateur"
@@ -1879,22 +1901,22 @@ msgid "SCSI Adapter"
msgstr "Adaptateur SCSI"
msgid "Please, wait..."
-msgstr "Vauillez patienter..."
+msgstr "Veuillez patienter..."
msgid "Add a Volume to Storage Pool"
-msgstr ""
+msgstr "iAjouter un Volume au Pool de Stockage"
msgid "Fetch from remote URL"
msgstr ""
msgid "Enter the remote URL here."
-msgstr ""
+msgstr "Saisir une URL distante ici"
msgid "Upload an file"
-msgstr ""
+msgstr "Charger un fichier"
msgid "Choose the ISO file (with .iso suffix) you want to upload."
-msgstr ""
+msgstr "Sélectionner le fichier ISO (avec suffixe .iso) à charger"
msgid "Add Template"
msgstr "Ajouter un Modèle"
@@ -1906,7 +1928,7 @@ msgid "Local ISO Image"
msgstr "Image ISO Locale"
msgid "Local Image File"
-msgstr ""
+msgstr "Fichier Image Local"
msgid "Remote ISO Image"
msgstr "Image ISO Distante"
@@ -1918,13 +1940,13 @@ msgid "The following ISOs are available:"
msgstr "Les ISOs suivants sont disponibles:"
msgid "OS: "
-msgstr "OS:"
+msgstr "OS: "
msgid "Version: "
-msgstr "Version:"
+msgstr "Version: "
msgid "Size: "
-msgstr "Taille:"
+msgstr "Taille: "
msgid "Search more ISOs"
msgstr "Chercher plus d'ISOs"
@@ -1936,10 +1958,10 @@ msgid "I want to use a specific ISO file"
msgstr "Je veux utiliser un fichier ISO spécifique"
msgid "Loading default remote ISOs ..."
-msgstr "En cours de chargement des ISOs distants par défaut..."
+msgstr "Chargement des ISOs distants par défaut en cours..."
msgid "Arch: "
-msgstr "Arch:"
+msgstr "Arch: "
msgid "I want to use a custom URL"
msgstr "Je veux utiliser une URL personnalisée"
@@ -1957,7 +1979,7 @@ msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
-msgstr ""
+msgstr "Fichier Image"
msgid "Graphics"
msgstr "Graphiques"
@@ -2017,7 +2039,7 @@ msgid "Name should not contain '/' and '\"'."
msgstr "Le nom ne devrait pas contenir '/' et '\"'."
msgid "Isolated: no external network connection"
-msgstr "Isolated: pas de connexion à un réseau externe"
+msgstr "Isolé: pas de connexion à un réseau externe"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: connexion physique au réseau sortant uniquement"
@@ -2027,7 +2049,7 @@ msgstr ""
"Bridgé: Les macines virtuelles sont connectées directement au réseau physique"
msgid "(No interfaces found)"
-msgstr ""
+msgstr "(Aucune interface trouvée)"
msgid "Destination"
msgstr "Destination"
@@ -2063,13 +2085,13 @@ msgid "Activate"
msgstr "Activer"
msgid "Add Volume"
-msgstr ""
+msgstr "Ajouter un Volume"
msgid "Extend"
msgstr "Étendre"
msgid "Undefine"
-msgstr "Indéfini"
+msgstr "Supprimer"
msgid "Format"
msgstr "Format"
--
2.1.2
10 years
[PATCH V3] New MockModel
by Aline Manera
V2 -> V3:
- Fix "make check-local" errors
- Fix typo
V1 -> V2:
- Fix some tests cases
- Update volune ref_cnt when VM is deleted
Aline Manera (1):
MockModel refactor: Create MockModel based on Model("test:///default")
src/kimchi/i18n.py | 2 -
src/kimchi/mockmodel.py | 1771 ++++++++-----------------------------------
src/kimchi/vmtemplate.py | 9 +-
tests/run_tests.sh.in | 18 +-
tests/test_authorization.py | 27 +-
tests/test_mockmodel.py | 60 +-
tests/test_model.py | 5 +
tests/test_rest.py | 254 +++----
8 files changed, 503 insertions(+), 1643 deletions(-)
--
1.9.3
10 years
[PATCH 0/2 v2] New MockModel
by Aline Manera
Now it is completely done! \o/
The new MockModel uses Model with the 'test:///default' URI.
I also needed to update some tests cases and the run_tests.sh.in scripts as
the new MockModel overrides some Model functions, the test_model.py must be the
first test to be run.
V1 -> V2:
- Fix some tests cases
- Update volune ref_cnt when VM is deleted
Aline Manera (2):
bug fix: Update storage volume ref_cnt when VM is deleted
MockModel refactor: Create MockModel based on Model("test:///default")
src/kimchi/mockmodel.py | 1771 ++++++++-----------------------------------
src/kimchi/model/vms.py | 16 +-
src/kimchi/vmtemplate.py | 9 +-
tests/run_tests.sh.in | 18 +-
tests/test_authorization.py | 27 +-
tests/test_mockmodel.py | 60 +-
tests/test_model.py | 5 +
tests/test_rest.py | 254 +++----
8 files changed, 518 insertions(+), 1642 deletions(-)
--
1.9.3
10 years
[PATCH v2 00/10] Add snapshot support
by Crístian Viana
This is the difference between this and the previous patchset (v1):
- Use "dict.get(key, default_value)" instead of handling "dict[key]"
in a try/except block when the key doesn't exist.
- Remove the mention of a parameter in the snapshot method DELETE because it
wasn't implemented.
- Fix documentation, including mispelled words.
- Rebased to the latest revision (bde438e).
Crístian Viana (10):
Update clone test
snapshot: Create domain snapshots
snapshot: Lookup a domain snapshot
snapshot: List domain snapshots
snapshot: Delete a domain snapshot
snapshot: Lookup current snapshot on a domain
snapshot: Revert a domain to a snapshot
snapshot: Add model tests
snapshot: Delete snapshots when deleting a VM
snapshot: Clone snapshots when cloning a VM
docs/API.md | 27 ++++++
src/kimchi/control/vm/snapshots.py | 58 ++++++++++++
src/kimchi/i18n.py | 10 ++
src/kimchi/mockmodel.py | 90 ++++++++++++++++++
src/kimchi/model/vms.py | 47 +++++++++-
src/kimchi/model/vmsnapshots.py | 185 +++++++++++++++++++++++++++++++++++++
tests/test_model.py | 74 ++++++++++++++-
tests/test_rest.py | 100 ++++++++++++++++++++
8 files changed, 589 insertions(+), 2 deletions(-)
create mode 100644 src/kimchi/control/vm/snapshots.py
create mode 100644 src/kimchi/model/vmsnapshots.py
--
1.9.3
10 years
UI Mockup of SMT
by Yu Xin Huo
x86
Power(for SMT, I think it is single selection)
10 years