RFC - Guest memory usage
by Daniel Henrique Barboza
I was looking at the following item in the backlog:
Guests Stats: Display memory utilization (use virt-df or virt-top or ...)
If I understood it right, the idea here is to show the -inner- memory
allocation of the guest. If you have a VM with 4Gb of RAM running an
Ubuntu, we want to know how much memory the Ubuntu OS and its processes
are using.
I've done an investigation and I haven't found any tool to accomplish
this. "virt-top", "virsh dommemstat" and the libvirt API retrieves the
information of the memory usage of the guest relative to the host. In
the example mentioned before, supposing that the host has 64Gb of RAM,
all these tools would show that the VM is using 12% of the host RAM.
They do not dive in the VM and shows the actual mem usage of the Ubuntu
and its processes running there.
Haven't found anything useful in other MLs and forums. The common answer
is 'run top in a terminal inside the VM', which of course does not suit
us. My question is: any thoughts about how we can implement this
feature? Because I am starting to think that, in the end, this kind of
info is strict to the guest OS and can't be polled from the outside.
Thanks!
9 years, 2 months
[RFC] New API to create a random guest console password
by Aline Manera
Today user may set/change the guest console password and also its
expiration time through Kimchi API.
When passing an empty password, a random password is automatically
generated.
curl -u <user:password> -H "Content-Type: application/json" -H "Accept:
application/json"
http://localhost:8010/vms/blah -X PUT -d'{"graphics": {"passwd": ""}}'
That way is difficult to handle when user wants to reset the guest password.
We have a similar issue when we automatically change the passwdValidTo
when it is expired - increasing it in 30 seconds.
My proposal is simple: only change "passwd" and "passwdValidTo" when
user wants to do it.
curl -u <user:password> -H "Content-Type: application/json" -H "Accept:
application/json"
http://localhost:8010/vms/blah -X PUT -d'{"graphics": {"passwd":
"123456", "passwdValidTo": "<some datetime format>"}}'
curl -u <user:password> -H "Content-Type: application/json" -H "Accept:
application/json"
http://localhost:8010/vms/blah -X PUT -d'{"graphics":
{"passwdValidTo": "<some datetime format>"}}'
And make sure the passwdValidTo is only acceptable when there is a
passwd set.
And to reset those values, we only need to send an empty string:
curl -u <user:password> -H "Content-Type: application/json" -H "Accept:
application/json"
http://localhost:8010/vms/blah -X PUT -d'{"graphics": {"password":
"", "passwdValidTo": ""}}'
And create a new API: POST /vms/blah/ticket to automatically generate a
random password valid only for 30 seconds.
curl -u <user:password> -H "Content-Type: application/json" -H "Accept:
application/json"
http://localhost:8010/vms/blah/ticket -X POST -d'{}'
What do you think about it?
Regards,
Aline Manera
9 years, 8 months
CPU discussion (RE: psutil.NUM_CPUS)
by Christy Perez
After my confusion on Paulo's patch a few weeks ago, I thought I had
just gotten confused, and so I put psutil.NUM_CPUS in my SMT/HT patch.
However, testing now on x86, I'm noticing a difference in the way Power
and x86 report CPUS.
On my laptop:
<cpu>
<arch>x86_64</arch>
<model>SandyBridge</model>
<vendor>Intel</vendor>
<topology sockets='1' cores='2' threads='2'/>
psutil.NUM_CPUS returns 4
On a Power7 system with 16 cores, 4 threads/core (so 64 total threads),
psutil.NUM_CPUS returns 16.
And this is, it turns out, because (and this sounds odd) for *guests* to
be able to do SMT on Power, SMT has to be disabled. So, psutil.NUM_CPUS
will not report the number of vCPUs that are available to guests. The
same change would happen on x86 if you disabled HT, I assume.
So, revisiting this difference that I noticed but wasn't able to
articulate very well last time, do we want to make a change to the host
code to use ppc64_cpu if the arch is Power, instead of psutil.NUM_CPUS?
SMT *is* off, so, technically this isn't correct, but I think we should
provide this information with guests in mind since we are a
virtualization platform.
Regards,
- Christy
9 years, 11 months
[PATCH] Delete reference count when deleting storage volume
by lvroyce@linux.vnet.ibm.com
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
If ref count remains in system after volume delete, it will cause
side effect in creating a volume of same name.
Fix this by deleting reference count when deleting storage volume.
Signed-off-by: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
---
src/kimchi/model/diskutils.py | 13 +++++++++++++
src/kimchi/model/storagevolumes.py | 3 ++-
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/kimchi/model/diskutils.py b/src/kimchi/model/diskutils.py
index 1d575cb..7eb24d2 100644
--- a/src/kimchi/model/diskutils.py
+++ b/src/kimchi/model/diskutils.py
@@ -73,3 +73,16 @@ def set_disk_ref_cnt(objstore, path, new_count):
session.store('storagevolume', path, {'ref_cnt': new_count})
except Exception as e:
raise OperationFailed('KCHVOL0017E', {'err': e.message})
+
+
+def clean_disk_ref_cnt(objstore, path):
+ try:
+ with objstore as session:
+ session.delete('storagevolume', path)
+ except NotFoundError:
+ pass
+ except Exception as e:
+ kimchi_log.error('Unable to delete storage volume in'
+ ' objectstore due error: %s',
+ e.message)
+ raise OperationFailed('KCHVOL0017E', {'err': e.message})
diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py
index 406b38b..cf83b0e 100644
--- a/src/kimchi/model/storagevolumes.py
+++ b/src/kimchi/model/storagevolumes.py
@@ -30,7 +30,7 @@ from kimchi.config import READONLY_POOL_TYPE
from kimchi.exception import InvalidOperation, InvalidParameter, IsoFormatError
from kimchi.exception import MissingParameter, NotFoundError, OperationFailed
from kimchi.isoinfo import IsoImage
-from kimchi.model.diskutils import get_disk_ref_cnt
+from kimchi.model.diskutils import get_disk_ref_cnt, clean_disk_ref_cnt
from kimchi.model.storagepools import StoragePoolModel
from kimchi.model.tasks import TaskModel
from kimchi.utils import add_task, get_next_clone_name, kimchi_log
@@ -306,6 +306,7 @@ class StorageVolumeModel(object):
raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})
volume = self._get_storagevolume(pool, name)
+ clean_disk_ref_cnt(self.objstore, volume.path())
try:
volume.delete(0)
except libvirt.libvirtError as e:
--
1.9.3
9 years, 11 months
[PATCH 0/3] Issue #544
by Crístian Viana
This is the first patchset which fixes the issue #544. After applying these
patches, the user can now download image files to a logical storage pool.
However, they cannot create a template with it because (1) the UI filters the
storage volumes and only displays the ones with format='iso' and storage volumes
stored in a logical pool always have format='raw', and (2) the template classes
fail to identify logical volumes as files because they're symlinks.
Editing an existing VM's XML to use the storage volume downloaded to a logical
pool works, though.
Crístian Viana (3):
Change "_get_storagevolume" to static
Use 'bytes' as volume capacity and allocation unit
issue #544: Refactor storage volume download
docs/API.md | 4 +-
src/kimchi/model/storagevolumes.py | 75 +++++++++++++++++++++++++++++++-------
tests/test_model.py | 19 +++++-----
tests/test_rest.py | 12 +++---
4 files changed, 78 insertions(+), 32 deletions(-)
--
2.1.0
9 years, 11 months
Kimchi UI Design Update
by Don S. Spangler
All --
I have updated the Kimchi UI design wiki page (UI Design
<https://github.com/kimchi-project/kimchi/wiki/UI-Design-Proposals>)
with the latest design covering blueprints (icons / graphics, font,
color, layout) and interactions for all tabs. Included as well are
specific task panels with the design style applied (more panels will be
included as we go and can work on specific ones earlier on request).
There is ongoing work which will cover responsiveness which will be
posted separately when it is completed.
Thanks again to everyone for their feedback on the initial version and
we look forward to your thoughts on these updates.
Don Spangler
9 years, 11 months
[PATCH 0/5] Bug fixes and network tests
by Aline Manera
Aline Manera (5):
Add message to KCHNET0010E code
Bug fix: Allow deleting VLAN tagging bridged network
Network API: Update docs/API.md
Move rollback_wrapper function to a common place
Reorganize the network tests
docs/API.md | 11 ++--
src/kimchi/i18n.py | 1 +
src/kimchi/model/networks.py | 6 +-
tests/test_model.py | 86 ++-----------------------
tests/test_network.py | 147 +++++++++++++++++++++++++++++++++++++++++++
tests/test_rest.py | 64 -------------------
tests/utils.py | 15 ++++-
7 files changed, 175 insertions(+), 155 deletions(-)
create mode 100644 tests/test_network.py
--
2.1.0
9 years, 11 months
[PATCH] <Fix problems of edit a guest contains snapshots>
by gouzongmei@ourfuture.cn
From: Zongmei Gou <gouzongmei(a)ourfuture.cn>
---
src/kimchi/control/base.py | 13 ++++++++++---
src/kimchi/model/vms.py | 24 ++++++++++++++++++------
src/kimchi/model/vmsnapshots.py | 8 ++++++--
src/kimchi/xmlutils/utils.py | 5 +++++
4 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py
index 60db1df..ff31d47 100644
--- a/src/kimchi/control/base.py
+++ b/src/kimchi/control/base.py
@@ -58,10 +58,17 @@ class Resource(object):
self.role_key = None
self.admin_methods = []
- def _redirect(self, ident, code=303):
- if ident is not None and ident != self.ident:
+ def _redirect(self, action_result, code=303):
+ if isinstance(action_result, list):
+ uri_params = []
+ for arg in action_result:
+ if arg is None:
+ arg = ''
+ uri_params.append(urllib2.quote(arg.encode('utf-8'),safe=""))
+ raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), code)
+ elif action_result is not None and action_result != self.ident:
uri_params = list(self.model_args[:-1])
- uri_params += [urllib2.quote(ident.encode('utf-8'), safe="")]
+ uri_params += [urllib2.quote(action_result.encode('utf-8'), safe="")]
raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), code)
def generate_action_handler(self, action_name, action_args=None):
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index 3aa1145..0caa1fd 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -668,22 +668,34 @@ class VMModel(object):
new_xml = self._update_graphics(dom, new_xml, params)
conn = self.conn.get()
+ snapshot_xmls = []
try:
if 'name' in params:
- if state == 'running':
- msg_args = {'name': dom.name(), 'new_name': params['name']}
- raise InvalidParameter("KCHVM0003E", msg_args)
-
- # Undefine old vm, only if name is going to change
- dom.undefine()
+ new_name = params['name']
+ name = dom.name()
+ if new_name != name:
+ if state == 'running':
+ raise InvalidParameter("KCHVM0003E", {'name': name, 'new_name': new_name})
+
+ # get snapshots before vm undefine, original snapshots will be created in the new named vm
+ snapshot_names = dom.snapshotListNames(0)
+ for snapshot_name in snapshot_names:
+ vir_snap = self.vmsnapshot.get_vmsnapshot(name, snapshot_name)
+ snapshot_xmls.append(vir_snap.getXMLDesc(0))
+ # Undefine old vm, only if name is going to change
+ dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)
root = ET.fromstring(new_xml)
currentMem = root.find('.currentMemory')
if currentMem is not None:
root.remove(currentMem)
dom = conn.defineXML(ET.tostring(root, encoding="utf-8"))
+ for snapshot_xml in snapshot_xmls:
+ dom.snapshotCreateXML(snapshot_xml, 1)
except libvirt.libvirtError as e:
dom = conn.defineXML(old_xml)
+ for snapshot_xml in snapshot_xmls:
+ dom.snapshotCreateXML(snapshot_xml, 1)
raise OperationFailed("KCHVM0008E", {'name': dom.name(),
'err': e.get_error_message()})
return dom
diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py
index 725770d..569c7ad 100644
--- a/src/kimchi/model/vmsnapshots.py
+++ b/src/kimchi/model/vmsnapshots.py
@@ -29,7 +29,7 @@ from kimchi.model.tasks import TaskModel
from kimchi.model.vms import DOM_STATE_MAP, VMModel
from kimchi.model.vmstorages import VMStorageModel, VMStoragesModel
from kimchi.utils import add_task
-
+from kimchi.xmlutils.utils import xml_item_get
class VMSnapshotsModel(object):
def __init__(self, **kargs):
@@ -155,7 +155,11 @@ class VMSnapshotModel(object):
try:
vir_dom = VMModel.get_vm(vm_name, self.conn)
vir_snap = self.get_vmsnapshot(vm_name, name)
- vir_dom.revertToSnapshot(vir_snap, 0)
+ ret = vir_dom.revertToSnapshot(vir_snap, 0)
+ if ret == 0:
+ xmlObj = vir_snap.getXMLDesc(0)
+ new_vmname = xml_item_get(xmlObj, 'domain/name')
+ return [new_vmname, name]
except libvirt.libvirtError, e:
raise OperationFailed('KCHSNAP0009E', {'name': name,
'vm': vm_name,
diff --git a/src/kimchi/xmlutils/utils.py b/src/kimchi/xmlutils/utils.py
index be08a14..843a113 100644
--- a/src/kimchi/xmlutils/utils.py
+++ b/src/kimchi/xmlutils/utils.py
@@ -65,3 +65,8 @@ def _dictize(e):
else:
d[child.tag] = _dictize(child)
return d
+
+def xml_item_get(xml, xpath):
+ root = ET.fromstring(xml)
+ item = root.find(xpath)
+ return item.text
--
1.7.1
9 years, 11 months
[PATCH V2] Po support: translation for Chinese
by Wen Wang
V1 -> V2:
Minor wording changes.
Added Chinese translation in po file.
Signed-off-by: Wen Wang <wenwang(a)linux.vnet.ibm.com>
---
po/zh_CN.po | 118 +++++++++++++++++++++++++++++++++---------------------------
1 file changed, 65 insertions(+), 53 deletions(-)
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 9bf50b8..0766585 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-12-15 11:01-0200\n"
+"POT-Creation-Date: 2014-12-18 17:08+0800\n"
"PO-Revision-Date: 2013-06-27 10:48+0000\n"
"Last-Translator: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>\n"
"Language-Team: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>\n"
@@ -75,7 +75,7 @@ msgstr "由于错误%(err)s任务启动失败"
#, python-format
msgid "Timeout of %(seconds)s seconds expired while running task '%(task)s."
-msgstr ""
+msgstr "任务'%(task)s超时%(seconds)s秒。"
#, python-format
msgid "Authentication failed for user '%(username)s'. [Error code: %(code)s]"
@@ -90,20 +90,20 @@ msgstr "指定登录Kimchi的%(item)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
-msgstr ""
+msgstr "使用指定的LDAP配置未找到%(user_id)s用户"
#, python-format
msgid "Invalid LDAP configuration: %(item)s : %(value)s"
-msgstr ""
+msgstr "无效的LDAP配置:%(item)s : %(value)s"
msgid "Unknown \"_cap\" specified"
-msgstr ""
+msgstr "未识别的\"_cap\""
msgid "\"_passthrough\" should be \"true\" or \"false\""
-msgstr ""
+msgstr "\"_passthrough\"值应为\"true\"或者\"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
-msgstr ""
+msgstr "\"_passthrough_affected_by\"应为一个字符串型设备名"
#, python-format
msgid "Error while getting block devices. Details: %(err)s"
@@ -302,24 +302,24 @@ msgstr "客户机命令行密码有效时间必须是一个数字。"
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
-msgstr ""
+msgstr "虚拟机'%(name)s'在制作副本前必须关机。"
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
-msgstr ""
+msgstr "制作虚拟机'%(name)s'副本所需的磁盘空间不足"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
-msgstr ""
+msgstr "未能成功制作虚拟机'%(name)s'副本。详情:%(err)s"
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
-msgstr ""
+msgstr "虚拟机%(vmid)s未指明被分配的主机设备%(dev_name)s。"
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
-msgstr ""
+msgstr "主机设备%(dev_name)s不允许直接分配给虚拟机。"
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
@@ -328,9 +328,13 @@ msgid ""
"to your Kernel parameter in /boot/grub2/grub.conf. For AMD CPU, add iommu=pt "
"iommu=1."
msgstr ""
+"未找到IOMMU groups。主机PCI pass through需要IOMMU group才可以正确工作。请在"
+"BIOS设置里将Intel VT-d 或者 AMD IOMMU 设为使能,而后确认内核支持IOMMU。对于"
+"Intel CPU,在路径/boot/grub2/grub.conf中添加内核变量intel_iommu=on。对于AMD "
+"CPU,则添加iommu=pt iommu=1。"
msgid "\"name\" should be a device name string"
-msgstr ""
+msgstr "\"name\"应该为一个字符串型的设备名"
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
@@ -444,17 +448,19 @@ msgstr "未能识别基础镜像%(path)s格式"
msgid ""
"When specifying CPU topology, VCPUs must be a product of sockets, cores, and "
"threads."
-msgstr ""
+msgstr "CPU拓扑中,VCPUs必须包括sockets, cores 以及threads。"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
-msgstr ""
+msgstr "CPU拓扑中,每一个参数必须为大于零的整数。"
msgid ""
"Invalid disk image format. Valid formats: bochs, cloop, cow, dmg, qcow, "
"qcow2, qed, raw, vmdk, vpc."
msgstr ""
+"无效的磁盘镜像格式。有效的格式为:bochs, cloop, cow, dmg, qcow, qcow2, qed, "
+"raw, vmdk, vpc。"
#, python-format
msgid "Storage pool %(name)s already exists"
@@ -660,6 +666,8 @@ msgid ""
"Storage volume format not supported. Valid formats: bochs, cloop, cow, dmg, "
"qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
+"不支持该存储卷格式,支持的格式:bochs, cloop, cow, dmg, qcow, qcow2, qed, "
+"raw, vmdk, vpc。"
msgid "Storage volume requires a volume name"
msgstr "存储卷需要名字"
@@ -685,13 +693,13 @@ msgstr "存储卷URL必须为http://,https://,ftp://或ftps://"
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
-msgstr ""
+msgstr "不能访问文件%(url)s,请检查该文件是否存在。"
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能于存储池'%(pool)s'制作存储卷'%(name)s'的副本,详情:%(err)s"
#, python-format
msgid "Interface %(name)s does not exist"
@@ -778,7 +786,7 @@ msgstr "网络接口%(iface)s启动失败,请检查网络连接情况。"
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
-msgstr ""
+msgstr "启动网络%(name)s失败,详情:%(err)s"
#, python-format
msgid "Debug report %(name)s does not exist"
@@ -838,7 +846,7 @@ msgid "Node device '%(name)s' not found"
msgstr "没有找到节点设备'%(name)s'"
msgid "Conflicting flag filters specified."
-msgstr ""
+msgstr "flag filters冲突。"
msgid "No packages marked for update"
msgstr "没有软件包标识要升级"
@@ -1035,60 +1043,62 @@ msgstr "软件仓库不支持配置类型: %(items)s"
#, python-format
msgid ""
"Virtual machine '%(vm)s' must be stopped before creating a snapshot of it."
-msgstr ""
+msgstr "虚拟机'%(vm)s'在制作快照前必须关机。"
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能为虚拟机'%(vm)s'制作快照'%(name)s'。详情:%(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
-msgstr ""
+msgstr "快照'%(name)s'不存在虚拟机'%(vm)s'上。"
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能在虚拟机'%(vm)s'找到快照'%(name)s'。详情:%(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
-msgstr ""
+msgstr "未能列出虚拟机'%(vm)s'的快照。详情:%(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能删除虚拟机'%(vm)s'快照'%(name)s'。详情:%(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能找到虚拟机'%(vm)s'当前快照。详情:%(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
-msgstr ""
+msgstr "未能恢复虚拟机'%(vm)s'到快照'%(name)s'。详情:%(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
+"未能为虚拟机'%(vm)s'创建快照因为其使用了格式为'%(format)s'的磁盘;当前仅支"
+"持'qcow2'格式。"
msgid "The number of vCPUs is too large for this system."
-msgstr ""
+msgstr "vCPUs的数量对该系统而言太大。"
msgid "Invalid vCPU/topology combination."
-msgstr ""
+msgstr "无效的vCPU/topology组合。"
msgid "This host (or current configuration) does not allow CPU topology."
-msgstr ""
+msgstr "当前主机(或当前配置)不允许CPU拓扑。"
msgid "ERROR CODE"
msgstr "错误码"
@@ -1159,10 +1169,10 @@ msgid "Permission"
msgstr "权限"
msgid "Host PCI Device"
-msgstr ""
+msgstr "主机PCI设备"
msgid "Snapshot"
-msgstr ""
+msgstr "快照"
msgid "Name"
msgstr "名称"
@@ -1195,28 +1205,28 @@ msgid "Selected system users and groups"
msgstr "已选的系统用户及用户组"
msgid "User"
-msgstr ""
+msgstr "用户"
msgid "All"
msgstr "所有"
msgid "To Add"
-msgstr ""
+msgstr "待添加"
msgid "Added"
-msgstr ""
+msgstr "已添加"
msgid "filter"
-msgstr ""
+msgstr "过滤器"
msgid "Product"
-msgstr ""
+msgstr "产品"
msgid "Vendor"
msgstr "厂商"
msgid "Created"
-msgstr ""
+msgstr "创建于"
msgid "Save"
msgstr "保存"
@@ -1231,10 +1241,10 @@ msgid "Cancel"
msgstr "取消"
msgid "revert"
-msgstr ""
+msgstr "恢复"
msgid "Cloning"
-msgstr ""
+msgstr "正在制作副本"
msgid "Start"
msgstr "启用"
@@ -1538,6 +1548,8 @@ msgid ""
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
+"当目标客户机使用SCSI或者iSCSI存储卷时,这些存储卷的副本将被放置于默认存储池"
+"中。在目标存储池没有足够空间放置其他存储卷的时候也会如此。确认继续?"
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
@@ -1565,25 +1577,25 @@ msgid ""
msgstr "该磁盘将会被永久卸载,你可以重新添加它,继续执行卸载操作吗?"
msgid "interface:"
-msgstr ""
+msgstr "接口:"
msgid "address:"
-msgstr ""
+msgstr "地址:"
msgid "link_type:"
-msgstr ""
+msgstr "连接类型:"
msgid "block:"
-msgstr ""
+msgstr "块:"
msgid "drive_type:"
-msgstr ""
+msgstr "设备类型:"
msgid "model:"
-msgstr ""
+msgstr "模型:"
msgid "Affected devices:"
-msgstr ""
+msgstr "被影响的设备:"
msgid "The VLAN id must be between 1 and 4094."
msgstr "VLAN 标识符必须在1至4094之间"
@@ -1872,7 +1884,7 @@ msgid "Upload a file"
msgstr "上传一个文件"
msgid "Choose the file you want to upload."
-msgstr ""
+msgstr "选择需要上传的文件。"
msgid "Add Template"
msgstr "创建模板"
@@ -1938,19 +1950,19 @@ msgid "Graphics"
msgstr "图形"
msgid "Disk(GB)"
-msgstr ""
+msgstr "磁盘(GB)"
msgid "CPU Number"
msgstr "CPU个数"
msgid "Manually set CPU topology"
-msgstr ""
+msgstr "手动配置CPU拓扑"
msgid "Cores"
-msgstr ""
+msgstr "内核数"
msgid "Threads"
-msgstr ""
+msgstr "线程"
msgid "CPU"
msgstr "处理器"
@@ -1983,7 +1995,7 @@ msgid "OS Code Name"
msgstr "操作系统代号"
msgid "CPU(s)"
-msgstr ""
+msgstr "CPU(s)"
msgid "System Statistics"
msgstr "系统统计信息"
--
1.9.3
9 years, 11 months
Re: [Kimchi-devel] [PATCH] <Fix problems of edit a guest contains snapshots>
by Aline Manera
The patch seems good for me.
I will just wait for a reply from Cristian as he was working on it.
On 20/12/2014 04:26, gouzongmei(a)ourfuture.cn wrote:
> From: Zongmei Gou <gouzongmei(a)ourfuture.cn>
>
> ---
> src/kimchi/control/base.py | 13 ++++++++++---
> src/kimchi/model/vms.py | 24 ++++++++++++++++++------
> src/kimchi/model/vmsnapshots.py | 8 ++++++--
> src/kimchi/xmlutils/utils.py | 5 +++++
> 4 files changed, 39 insertions(+), 11 deletions(-)
>
> diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py
> index 60db1df..ff31d47 100644
> --- a/src/kimchi/control/base.py
> +++ b/src/kimchi/control/base.py
> @@ -58,10 +58,17 @@ class Resource(object):
> self.role_key = None
> self.admin_methods = []
>
> - def _redirect(self, ident, code=303):
> - if ident is not None and ident != self.ident:
> + def _redirect(self, action_result, code=303):
> + if isinstance(action_result, list):
> + uri_params = []
> + for arg in action_result:
> + if arg is None:
> + arg = ''
> + uri_params.append(urllib2.quote(arg.encode('utf-8'),safe=""))
> + raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), code)
> + elif action_result is not None and action_result != self.ident:
> uri_params = list(self.model_args[:-1])
> - uri_params += [urllib2.quote(ident.encode('utf-8'), safe="")]
> + uri_params += [urllib2.quote(action_result.encode('utf-8'), safe="")]
> raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), code)
>
> def generate_action_handler(self, action_name, action_args=None):
> diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
> index 3aa1145..0caa1fd 100644
> --- a/src/kimchi/model/vms.py
> +++ b/src/kimchi/model/vms.py
> @@ -668,22 +668,34 @@ class VMModel(object):
> new_xml = self._update_graphics(dom, new_xml, params)
>
> conn = self.conn.get()
> + snapshot_xmls = []
> try:
> if 'name' in params:
> - if state == 'running':
> - msg_args = {'name': dom.name(), 'new_name': params['name']}
> - raise InvalidParameter("KCHVM0003E", msg_args)
> -
> - # Undefine old vm, only if name is going to change
> - dom.undefine()
> + new_name = params['name']
> + name = dom.name()
> + if new_name != name:
> + if state == 'running':
> + raise InvalidParameter("KCHVM0003E", {'name': name, 'new_name': new_name})
> +
> + # get snapshots before vm undefine, original snapshots will be created in the new named vm
> + snapshot_names = dom.snapshotListNames(0)
> + for snapshot_name in snapshot_names:
> + vir_snap = self.vmsnapshot.get_vmsnapshot(name, snapshot_name)
> + snapshot_xmls.append(vir_snap.getXMLDesc(0))
> + # Undefine old vm, only if name is going to change
> + dom.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)
>
> root = ET.fromstring(new_xml)
> currentMem = root.find('.currentMemory')
> if currentMem is not None:
> root.remove(currentMem)
> dom = conn.defineXML(ET.tostring(root, encoding="utf-8"))
> + for snapshot_xml in snapshot_xmls:
> + dom.snapshotCreateXML(snapshot_xml, 1)
> except libvirt.libvirtError as e:
> dom = conn.defineXML(old_xml)
> + for snapshot_xml in snapshot_xmls:
> + dom.snapshotCreateXML(snapshot_xml, 1)
> raise OperationFailed("KCHVM0008E", {'name': dom.name(),
> 'err': e.get_error_message()})
> return dom
> diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py
> index 725770d..569c7ad 100644
> --- a/src/kimchi/model/vmsnapshots.py
> +++ b/src/kimchi/model/vmsnapshots.py
> @@ -29,7 +29,7 @@ from kimchi.model.tasks import TaskModel
> from kimchi.model.vms import DOM_STATE_MAP, VMModel
> from kimchi.model.vmstorages import VMStorageModel, VMStoragesModel
> from kimchi.utils import add_task
> -
> +from kimchi.xmlutils.utils import xml_item_get
>
> class VMSnapshotsModel(object):
> def __init__(self, **kargs):
> @@ -155,7 +155,11 @@ class VMSnapshotModel(object):
> try:
> vir_dom = VMModel.get_vm(vm_name, self.conn)
> vir_snap = self.get_vmsnapshot(vm_name, name)
> - vir_dom.revertToSnapshot(vir_snap, 0)
> + ret = vir_dom.revertToSnapshot(vir_snap, 0)
> + if ret == 0:
> + xmlObj = vir_snap.getXMLDesc(0)
> + new_vmname = xml_item_get(xmlObj, 'domain/name')
> + return [new_vmname, name]
> except libvirt.libvirtError, e:
> raise OperationFailed('KCHSNAP0009E', {'name': name,
> 'vm': vm_name,
> diff --git a/src/kimchi/xmlutils/utils.py b/src/kimchi/xmlutils/utils.py
> index be08a14..843a113 100644
> --- a/src/kimchi/xmlutils/utils.py
> +++ b/src/kimchi/xmlutils/utils.py
> @@ -65,3 +65,8 @@ def _dictize(e):
> else:
> d[child.tag] = _dictize(child)
> return d
> +
> +def xml_item_get(xml, xpath):
> + root = ET.fromstring(xml)
> + item = root.find(xpath)
> + return item.text
9 years, 12 months