
Thanks for your review. 于 2014年11月14日 01:54, Crístian Viana 写道:
On 13-11-2014 05:02, simonjin@linux.vnet.ibm.com wrote:
+ "KCHVM0043E": _("Failed destory vm %(name)s from migration recover. Details: %(err)s"),
*destroy
@@ -33,6 +33,7 @@ from cherrypy.process.plugins import BackgroundTask from kimchi import model, vnc from kimchi.config import READONLY_POOL_TYPE from kimchi.exception import InvalidOperation, InvalidParameter +from kimchi.model.libvirtconnection import LibvirtConnection from kimchi.exception import NotFoundError, OperationFailed from kimchi.model.config import CapabilitiesModel from kimchi.model.tasks import TaskModel
We keep import statements sorted in alphabetical order. You need to move the line "from kimchi.model.libvirtconnection..." two lines below, right between "from kimchi.model.config..." and "from kimchi.model.tasks...", in alphabetical order.
OK
+ raise OperationFailed("KCHVM0036E", {'name': name, + 'remoteHost': remoteHost})
The error message KCHVM0036E, in src/kimchi/i18n.py, doesn't contain the format masks 'name' and 'remoteHost' as provided in the exception above:
"KCHVM0036E": _("Can't migrate to localhost."),
You need to provide exactly the same parameters declared in the error message. You either don't pass 'name' and 'remoteHost' when building that exception or you add 'name' and 'remoteHost' somewhere in the error message.
+ destarch = _destConn.getInfo()[0] + if self.conn.get().getInfo()[0] != destarch: + kimchi_log.debug('vm %s can not migrate to different arch server.' % (name, destarch)) + raise OperationFailed("KCHVM0037E", {'name': name, + 'srcarch': self.conn.get().getInfo()[0], + 'destarch': destarch})
The code above is running "self.conn.get().getInfo()" more than once. You can store that value in a variable so you don't have to talk to libvirt multiple times. Actually, "self.conn" is used in more places later in the code, so that value can also be stored in a separate value. Try not to contact libvirt several times for the same information, it has a performance cost.
self.conn it self doesn't cost anything.
+ desthyp = _destConn.getType() + if self.conn.get().getType() != desthyp: + kimchi_log.debug('vm %s can not migrate to a different hypervisor' % name) + raise OperationFailed("KCHVM0038E", {'name': self.name, + 'srchyp':self.conn.get().getType(), + 'desthyp':desthyp})
Again, store the value from "self.conn.getType()" in a local variable so you don't need to contact libvirt repeatedly. "self.conn" should already be in a separate variable according to my comment above.
Also, the error message KCHVM0038E contains the format masks 'srchyp' and 'desthyp' but you're providing 'name' as well. Those parameters don't match.
And "self.name" is an invalid reference, you need to use the local variable "name".
+ #check if there is any passthrough devices belong to this vm + vmhostdevs = VMHostDevsModel(conn = self.conn)
Usually we keep the model objects as instance variables. That means that "vmhostdevs" should be declared in VMModel's constructor - along with many other model variables - as "self.vmhostdevs".
Due to the reason in code that VMHostDevsModel can't be imported at the top of the class, the workaround is import and get the instance here.
Another useful verification to be added to "_preCheck" is to allow only one migration per VM happening at the same time. In order to do that, you need to check if a task with the 'target_uri' = '/vms/<vm-name>/migrate' is already running; that's the URI used when creating a migration task later in this code.
Will do.
+ #open destination connect to migrate + @staticmethod + def _getRemoteConn(self, remoteHost, user, transport = 'ssh'): + duri = 'qemu+%s://%s@%s/system' % (transport, + user,remoteHost) + conn = LibvirtConnection(duri) + return conn
A @staticmethod shouldn't receive the parameter "self". You can read the section https://docs.python.org/2/library/functions.html#staticmethod to learn more about static methods in Python. When you need to call it, do something like:
VMModel._getRemoteConn(...)
Notice that the function is prefixed with the class, not the object instance, as its implementation doesn't depend on a specific instance.
OK
def _do_migrate(self, name, destConn, remoteHost, secure, cb):
This function is supposed to be executed from inside a Task. The parameters of such function should be, in that exact order:
def fn(cb, params):
where "params" is a dict containing the other parameters. That means that the parameters "name", "destConn", "remoteHost" and "secure" should be inside the dict "params", and you need to extract them from the dict before using them inside "_do_migrate".
OK
+ else: + kimchi_log.debug('Can not migrate vm %s when its in %s.' % (name, state)) + raise OperationFailed("KCHVM0041E", {'name': self.name})
The error message KCHVM0041E contains the format masks 'name' and 'state'. You need to provide both parameters when creating an exception with that message (i.e.'state' is missing).
Also, "self.name" is an invalid reference - use "name" instead.
OK
+ except libvirt.libvirtError as e: + kimchi_log.error('migrate %s to %s failed' % (name, + remoteHost)) + self._recover(cb) + raise OperationFailed('KCHVM0042E', {'err': e.message,
Are you sure that if an error occurs during migration, we need to undefine the remote domain? In my view, if the migration failed, there won't be a remote domain to undefine - well, it failed. And I couldn't find this on libvirt's documentation so I'm not sure of the behaviour in that case.
OK
+ finally: + self._finish(name, destConn, cb)
The function "_finish" is called from inside the "finally" block, which means it will be called regardless of whether an exception was raised or not. However, that function calls "cb(..., True)", which indicates that the task has finished successfully. We should not call "cb(..., True)" if an exception was raised and the migration failed.
+ destconn = self._getRemoteConn(remoteHost, user, passwd)
The function "_getRemoteConn" was defined as:
def _getRemoteConn(self, remoteHost, user, transport = 'ssh'):
The parameters provided above don't match the defined parameters. The function expects a transport method in its last parameter but the code above is passing a password instead.
+ # Record vm migrate task for future querying + try: + with self.objstore as session: + session.store('migrate', name, task_id) + return task_id + except Exception as e: + raise OperationFailed('KCHPOOL0037E', {'err': e.message})
As I commented in the previous e-mail thread, the function "add_task" will add the task to the object store. You don't need to do that.
Will need this to verify whether the vm is already in migration, right ?
Before sending every patch, you need to make sure it follows our code guideline. You can run the command "make check-local" on your shell and check its output. There are a few errors pointed out by that tool for this patch, so be sure to fix every one of them.
How do you test this code? Were you able to perform a VM migration successfully using this patch? You can try running the command below on your shell:
$ curl -s -k -u <username>:<password> -H 'Content-Type: application/json' -H 'Accept: application/json' https://localhost:8001/vms/<vm-name>/migrate -X POST -d '{"remoteHost": "<remote-host>", "user": "<remote-user>", "password": "<remote-password>", "secure": True}'
and make sure the migration actually happened.
Best regards, Crístian.