On 04/14/2014 06:53 AM, huoyuxin(a)linux.vnet.ibm.com wrote:
From: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
Add, List, Delete, Update Guest Network Interface.
Signed-off-by: Yu Xin Huo <huoyuxin(a)linux.vnet.ibm.com>
---
ui/css/theme-default/guest-edit.css | 43 +++++++++++++++
ui/js/src/kimchi.api.js | 55 +++++++++++++++++++
ui/js/src/kimchi.guest_edit_main.js | 103 +++++++++++++++++++++++++++++++++++
ui/pages/guest-edit.html.tmpl | 53 ++++++++++++++++++
4 files changed, 254 insertions(+), 0 deletions(-)
diff --git a/ui/css/theme-default/guest-edit.css b/ui/css/theme-default/guest-edit.css
index 0b7ba21..4b208c1 100644
--- a/ui/css/theme-default/guest-edit.css
+++ b/ui/css/theme-default/guest-edit.css
@@ -156,3 +156,46 @@
.guest-edit-cdrom-button.detach[disabled] {
background-position: -54px -108px;
}
+
+.guest-edit-interface .header {
+ margin-bottom: 8px;
+ padding-bottom: 2px;
+ font-weight: bold;
+ border-bottom: 1px solid #999999;
+ overflow: hidden;
+}
+
+.guest-edit-interface .body .item {
+ margin: 5px 0;
+}
+
+.guest-edit-interface .cell {
+ display: inline-block;
+ width: 150px;
+}
+
+.guest-edit-interface .body select {
+ width: 130px;
+ padding: 0px;
+}
+
+.guest-edit-interface .action-area {
+ float: right;
+}
+
+.guest-edit-interface button {
+ width: 20px;
+ height: 20px;
+}
+
+.guest-edit-interface .header button {
+ margin-bottom: 1px;
+}
+
+.guest-edit-interface .body button:not(:last-child) {
+ margin-right: 2px;
+}
+
+.guest-edit-interface .hide {
+ display: none;
+}
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 8c1030c..168e53d 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -955,5 +955,60 @@ var kimchi = {
kimchi.message.error(data.responseJSON.reason);
}
});
+ },
+
+ getGuestInterfaces: function(name, suc, err) {
+ var url =
kimchi.url+'/vms/'+encodeURIComponent(name)+'/ifaces';
+ kimchi.requestJSON({
+ url : url,
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err || function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ createGuestInterface : function(name, interface, suc, err) {
+ kimchi.requestJSON({
+ url :
kimchi.url+'/vms/'+encodeURIComponent(name)+'/ifaces',
+ type : 'POST',
+ contentType : 'application/json',
+ dataType : 'json',
+ data : JSON.stringify(interface),
+ success : suc,
+ error : err || function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ deleteGuestInterface : function(vm, mac, suc, err) {
+ kimchi.requestJSON({
+ url :
kimchi.url+'/vms/'+encodeURIComponent(vm)+'/ifaces/'+encodeURIComponent(mac),
+ type : 'DELETE',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ updateGuestInterface : function(vm, mac, interface, suc, err) {
+ $.ajax({
+ url :
kimchi.url+'/vms/'+encodeURIComponent(vm)+'/ifaces/'+encodeURIComponent(mac),
+ type : 'PUT',
+ contentType : 'application/json',
+ data : JSON.stringify(interface),
+ dataType : 'json',
+ success: suc,
+ error: err ? err : function(data) {
+ kimchi.message.error(data.responseJSON.reason);
+ }
+ });
The update API is not implemented on backend yet.
You can remove it.
}
};
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index 9375c51..b051774 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -78,6 +78,107 @@ kimchi.guest_edit_main = function() {
});
};
+ var setupInterface = function() {
+ $(".add", "#form-guest-edit-interface").button({
+ icons: { primary: "ui-icon-plusthick" },
+ text: false
+ }).click(function(){
+ addItem({
+ mac: "",
+ network: "",
+ model: "",
The model will be chosen by Kimchi automatically.
It is a low level information and we should not require it from user.
+ type: "",
+ viewMode: "hide",
+ editMode: ""
+ });
+ });
+ var toggleEdit = function(item, on){
+ $("label", item).toggleClass("hide", on);
+ $("select", item).toggleClass("hide", !on);
+ $(".action-area", item).toggleClass("hide");
+ };
+ var addItem = function(data) {
+ var attrs = ["network", "model", "type"];
+ var attrIndex = 0;
+ var itemNode =
$.parseHTML(kimchi.template($('#interface-tmpl').html(),data));
+ $(".body",
"#form-guest-edit-interface").append(itemNode);
+ $("select", itemNode).first().append(networkOptions);
+ if(data[attrs[attrIndex]]!=""){
+ $("select", itemNode).each(function(){
+ $(this).val(data[attrs[attrIndex]]);
+ attrIndex++;
+ });
+ attrIndex = 0;
+ }
+ $(".edit", itemNode).button({
+ icons: { primary: "ui-icon-pencil" },
+ text: false
+ }).click(function(){
+ toggleEdit($(this).parent().parent(), true);
+ });
+ $(".delete", itemNode).button({
+ icons: { primary: "ui-icon-trash" },
+ text: false
+ }).click(function(){
+ var item = $(this).parent().parent();
+ kimchi.deleteGuestInterface(kimchi.selectedGuest,
item.prop("id"), function(){
+ item.remove();
+ });
+ });
+ $(".save", itemNode).button({
+ icons: { primary: "ui-icon-disk" },
+ text: false
+ }).click(function(){
+ var interface = {};
+ var item = $(this).parent().parent();
+ $("select", item).each(function(){
+ interface[attrs[attrIndex]] = $(this).val();
+ attrIndex++;
+ });
+ attrIndex = 0;
+ var postUpdae = function(){
+ $("label", item).each(function(){
+ $(this).text(interface[attrs[attrIndex]]);
+ attrIndex++;
+ });
+ attrIndex = 0;
+ toggleEdit(item, false);
+ };
+ if(item.prop("id")==""){
+ kimchi.createGuestInterface(kimchi.selectedGuest, interface,
function(data){
+ item.prop("id", data.mac);
+ postUpdae();
+ });
+ }else{
+ kimchi.updateGuestInterface(kimchi.selectedGuest,
item.prop("id"), interface, function(){
+ postUpdae();
+ });
+ }
+ });
+ $(".cancel", itemNode).button({
+ icons: { primary: "ui-icon-arrowreturnthick-1-w" },
+ text: false
+ }).click(function(){
+ var item = $(this).parent().parent();
+ $("label", item).text()==="" ? item.remove() :
toggleEdit(item, false);
+ });
+ };
+ var networkOptions = "";
+ kimchi.listNetworks(function(data){
+ for(var i=0;i<data.length;i++){
+ var isSlected = i==0 ? " selected" : "";
+ networkOptions +=
"<option"+isSlected+">"+data[i].name+"</option>";
+ }
+ kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data){
+ for(var i=0;i<data.length;i++){
+ data[i].viewMode = "";
+ data[i].editMode = "hide";
+ addItem(data[i]);
+ }
+ });
+ });
+ };
+
var initContent = function(guest) {
guest['icon'] = guest['icon'] || 'images/icon-vm.png';
for ( var prop in guest) {
@@ -101,6 +202,8 @@ kimchi.guest_edit_main = function() {
refreshCDROMs();
};
+ setupInterface();
+
kimchi.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
kimchi.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
kimchi.topic('kimchi/vmCDROMDetached').subscribe(onDetached);
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index 804fc39..a2949be 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -35,6 +35,9 @@
<li>
<a
href="#form-guest-edit-storage">$_("Storage")</a>
</li>
+ <li>
+ <a
href="#form-guest-edit-interface">$_("Interface")</a>
+ </li>
</ul>
<form id="form-guest-edit-general">
<fieldset class="guest-edit-fieldset">
@@ -103,6 +106,15 @@
</div>
</fieldset>
</form>
+ <form id="form-guest-edit-interface"
class="guest-edit-interface">
+ <div class="header">
+ <span
class="cell">$_("Network")</span>
+ <span
class="cell">$_("Model")</span>
As I said before we should not require model info
+ <span
class="cell">$_("Type")</span>
+ <button class="add action-area"></button>
+ </div>
+ <div class="body"></div>
+ </form>
</div>
</div>
<footer>
@@ -133,6 +145,47 @@
</div>
</div>
</script>
+<script id="interface-tmpl" type="text/html">
+ <div class="item" id="{mac}">
+ <span class="cell">
+ <label class="{viewMode}">{network}</label>
+ <select class="{editMode}"></select>
+ </span>
+ <span class="cell">
+ <label
class="{viewMode}">{model}</label>
+ <select class="{editMode}">
+ <option>ne2k_pci</option>
+ <option>i82551</option>
+ <option>i82557b</option>
+ <option>i82559er</option>
+ <option selected>rtl8139</option>
+ <option>e1000</option>
+ <option>pcnet</option>
+ <option>virtio</option>
Same here.
+ </select>
+ </span>
+ <span class="cell">
+ <label class="{viewMode}">{type}</label>
+ <select class="{editMode}">
+ <option selected>network</option>
+ <option disabled>bridge</option>
+ <option disabled>user</option>
+ <option disabled>ethernet</option>
+ <option disabled>direct</option>
+ <option disabled>hostdev</option>
+ <option disabled>mcast</option>
+ <option disabled>server</option>
+ <option disabled>client</option>
+ </select>
+ </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 type="text/javascript">
kimchi.guest_edit_main();